java函数调用约定_2020-09-04:函数调用约定了解么?
福哥答案2020-09-04:
初級(jí)回答:
stdcall和cdecl兩者的參數(shù)傳遞順序都是從右向左。
不同點(diǎn)是stdcall在被調(diào)用函數(shù) (Callee) 返回前,由被調(diào)用函數(shù) (Callee) 調(diào)整堆棧。cdecl在被調(diào)用函數(shù) (Callee) 返回后,由調(diào)用方 (Caller) 調(diào)整堆棧,每一個(gè)調(diào)用它的函數(shù)都包含清空堆棧的代碼,所以產(chǎn)生的可執(zhí)行文件大小會(huì)比調(diào)用_stdcall函數(shù)的大。
中級(jí)回答:
1.__stdcall
在被調(diào)用函數(shù) (Callee) 返回前,由被調(diào)用函數(shù) (Callee) 調(diào)整堆棧
參數(shù)從右向左壓入堆棧。
函數(shù)名自動(dòng)加前導(dǎo)的下劃線,后面緊跟一個(gè)@符號(hào) ,其后緊跟著參數(shù)的尺寸。
2.__cdecl
在被調(diào)用函數(shù) (Callee) 返回后,由調(diào)用方 (Caller) 調(diào)整堆棧。
函數(shù)實(shí)參在線程棧上按照從右至左的順序依次壓棧。
函數(shù)結(jié)果保存在寄存器EAX/AX/AL中
浮點(diǎn)型結(jié)果存放在寄存器ST0中
編譯后的函數(shù)名前綴以一個(gè)下劃線字符
調(diào)用者負(fù)責(zé)從線程棧中彈出實(shí)參(即清棧)
8比特或者16比特長的整形實(shí)參提升為32比特長。
受到函數(shù)調(diào)用影響的寄存器(volatile registers):EAX, ECX, EDX, ST0 - ST7, ES, GS
不受函數(shù)調(diào)用影響的寄存器: EBX, EBP, ESP, EDI, ESI, CS, DS
RET指令從函數(shù)被調(diào)用者返回到調(diào)用者(實(shí)質(zhì)上是讀取寄存器EBP所指的線程棧之處保存的函數(shù)返回地址并加載到IP寄存器)
3.__fastcall
__fastcall調(diào)用的主要特點(diǎn)就是快,因?yàn)樗峭ㄟ^寄存器來傳送參數(shù)的。
實(shí)際上__fastcall用ECX和EDX傳送前兩個(gè)DWORD或更小的參數(shù),剩下的參數(shù)仍自右向左壓棧傳送,被調(diào)用的函數(shù)在返回前清理傳送參數(shù)的內(nèi)存棧。
__fastcall調(diào)用約定在輸出函數(shù)名前加上一個(gè)“@”符號(hào),后面也是一個(gè)“@”符號(hào)和其參數(shù)的字節(jié)數(shù),格式為@function @number ,如double multi(double a, double b)的修飾名是@multi@16。
__fastcall和__stdcall很象,唯一差別就是頭兩個(gè)參數(shù)通過寄存器傳送。注意通過寄存器傳送的兩個(gè)參數(shù)是從左向右的,即第1個(gè)參數(shù)進(jìn)ECX,第2個(gè)進(jìn)EDX,其他參數(shù)是從右向左的入棧,返回仍然通過EAX。
fastcall調(diào)用約定和stdcall類似,它意味著:
函數(shù)的第一個(gè)和第二個(gè)DWORD參數(shù)(或者尺寸更小的)通過ecx和edx傳遞,其他參數(shù)通過從右向左的順序壓棧;
被調(diào)用函數(shù)清理堆棧;
函數(shù)名修改規(guī)則同stdcall。
Fast Calling Convention,快速調(diào)用約定。通過使用寄存器解決效率問題。特點(diǎn):
函數(shù)參數(shù)部分通過寄存器傳遞,函數(shù)中最左的兩個(gè)DWORD(寄存器大小是雙字)或者更小的參數(shù),通過寄存器傳遞。剩下的從右到左堆棧傳遞。 函數(shù)名改編:“@函數(shù)名@函數(shù)參數(shù)字節(jié)大小十進(jìn)制”。 返回方式同__stdcall。
4.__thiscall
thiscall是唯一一個(gè)不能明確指明的函數(shù)修飾,因?yàn)閠hiscall不是關(guān)鍵字。它是C++類成員函數(shù)缺省的調(diào)用約定。由于成員函數(shù)調(diào)用還有一個(gè)this指針,因此必須特殊處理,thiscall意味著:
參數(shù)從右向左入棧;
如果參數(shù)個(gè)數(shù)確定,this指針通過ecx傳遞給被調(diào)用者;如果參數(shù)個(gè)數(shù)不確定,this指針在所有參數(shù)壓棧后被壓入堆棧;
對(duì)參數(shù)個(gè)數(shù)不定的,調(diào)用者清理堆棧,否則函數(shù)自己清理堆棧。
主要用于解決this指針問題,使用寄存器傳遞this指針。返回方式同__stdcall.
5.__nakedcall
這是一個(gè)很少見的調(diào)用約定,一般程序設(shè)計(jì)者建議不要使用。編譯器不會(huì)給這種函數(shù)增加初始化和清理代碼,更特殊的是,不能用return返回返回值,只能用插入?yún)R編返回結(jié)果。
6.__pascal
基于Pascal語言的調(diào)用約定,參數(shù)從左至右入棧(與cdecl相反)。被調(diào)用者負(fù)責(zé)在返回前清理堆棧。 此調(diào)用約定常見在如下16-bit 平臺(tái)的編譯器:OS/2 1.x,微軟Windows 3.x,以及Borland Delphi版本1.x。
7.__vectorcall
目的是用來優(yōu)化浮點(diǎn)向量運(yùn)算,intel處理器種有很多浮點(diǎn)向量寄存器,傳統(tǒng)的調(diào)用約定(stdcall cdecl fastcall thiscall) 都是通過通用寄存器(ecx edx /rcx rdx r8 r9)以及堆棧進(jìn)行參數(shù)傳遞,所以調(diào)用的時(shí)候,浮點(diǎn)參數(shù)需要從棧獲取。
要求盡可能在寄存器中傳遞參數(shù)。函數(shù)名改編為”@@函數(shù)名@參數(shù)字節(jié)數(shù)十進(jìn)制”。這是微軟自己添加的標(biāo)準(zhǔn)。
8.syscall
與cdecl類似,參數(shù)被從右到左推入堆棧中。EAX, ECX和EDX不會(huì)保留值。參數(shù)列表的大小被放置在AL寄存器中(?)。 syscall是32位OS/2 API的標(biāo)準(zhǔn)。
9.optlink
參數(shù)也是從右到左被推入堆棧。從最左邊開始的三個(gè)字符變?cè)獣?huì)被放置在EAX, EDX和ECX中,最多四個(gè)浮點(diǎn)變?cè)獣?huì)被傳入ST(0)到ST(3)中----雖然這四個(gè)參數(shù)的空間也會(huì)在參數(shù)列表的棧上保留。函數(shù)的返回值在EAX或ST(0)中。保留的寄存器有EBP, EBX, ESI和EDI。 optlink在IBM VisualAge編譯器中被使用。
10.__clrcall
__clrcall是C++ .Net里面的。
總結(jié)
以上是生活随笔為你收集整理的java函数调用约定_2020-09-04:函数调用约定了解么?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: node 后台重定向_登录后重定向到用户
- 下一篇: linux tar压缩包目录,如何在Li