1.如果函數(shù)func是__cdecl(C/C++默認(rèn)調(diào)用方式,實(shí)現(xiàn)可變參數(shù)函數(shù)),調(diào)用時(shí)情況如下
int main() ...{ //參數(shù)從右到左壓棧 push 4 push 3 push 2 push 1 call func add esp 0x10 //調(diào)用者恢復(fù)堆棧指針esp,4個(gè)參數(shù)的大小是0x10(4x4) }
2.如果函數(shù)func是__stdcall(最多語言支持的方式,COM規(guī)范標(biāo)準(zhǔn)),調(diào)用時(shí)情況如下
int main() ...{ //參數(shù)從右到左壓棧 push 4 push 3 push 2 push 1 call func //恢復(fù)堆棧指針由被調(diào)用者func負(fù)責(zé),方法是"ret 0x10" }
3.如果函數(shù)func是__pascal,調(diào)用情況如下
int main() ...{ //參數(shù)從左到右壓棧 push 1 push 2 push 3 push 4 call func //恢復(fù)堆棧指針由被調(diào)用者func負(fù)責(zé),方法是"ret 0x10" }
3.如果函數(shù)func是__fastcall(寄存器傳參),調(diào)用情況如下
int main() ...{ //參數(shù)先用ecx, edx, eax傳遞,然后再壓棧 //不進(jìn)棧 //(不知為什么,幫助中寫的是從左到右傳遞的, //是不是錯(cuò)了,還是bcb6和bcb5的不一樣) push 4 mov ecx 3 mov edx 2 mov eax 1 call func //恢復(fù)堆棧指針由被調(diào)用者func負(fù)責(zé),方法是"ret 0x04", //因?yàn)橹贿M(jìn)棧一個(gè)參數(shù),其余用寄存器傳遞,所以用ret 0x04恢復(fù) }
發(fā)表者:huang_jh
#define callback __stdcall #define winapi __stdcall 定義成不同的名字只是為了"望文知意"就像hwnd和hcursor是一樣的類型. 他們都是窗口函數(shù)(過程)......
發(fā)表者:sinman
我收集的,全仍上來了 左通過棧傳遞,被調(diào)用的函數(shù)在返回前清理傳送參數(shù)的內(nèi)存棧,但不同的是函數(shù)名的修飾部分。 _stdcall是pascal程序的缺省調(diào)用方式,通常用于win32 api中,函數(shù)采用從右到左的壓棧方式,自己在退出時(shí)清空堆棧。vc將函數(shù)編譯后會(huì)在函數(shù)名前面加上下劃線前綴,在函數(shù)名后加上"@"和參數(shù)的字節(jié)數(shù)。 2、c調(diào)用約定按從右至左的順序壓參數(shù)入棧,由調(diào)用者把參數(shù)彈出棧。對于傳送參數(shù)的內(nèi)存棧是由調(diào)用者來維護(hù)的。另外,在函數(shù)名修飾約定方面也有所不同。 _cdecl是c和c++程序的缺省調(diào)用方式。每一個(gè)調(diào)用它的函數(shù)都包含清空堆棧的代碼,所以產(chǎn)生的可執(zhí)行文件大小會(huì)比調(diào)用_stdcall函數(shù)的大。函 數(shù)采用從右到左的壓棧方式。vc將函數(shù)編譯后會(huì)在函數(shù)名前面加上下劃線前綴。是mfc缺省調(diào)用約定。 3、__fastcall調(diào)用約定是“人”如其名,它的主要特點(diǎn)就是快,因?yàn)樗峭ㄟ^寄存器來傳送參數(shù)的或更小的參數(shù),剩下的參數(shù)仍舊自右向左壓棧傳送,被調(diào)用的函數(shù)在返回前清理傳送參數(shù)的內(nèi)存棧),在函數(shù)名修飾約定方面,它和前兩者均不同。 _fastcall方式的函數(shù)采用寄存器傳遞參數(shù),vc將函數(shù)編譯后會(huì)在函數(shù)名前面加上"@"前綴,在函數(shù)名后加上"@"和參數(shù)的字節(jié)數(shù)。 4、thiscall僅僅應(yīng)用于“c++”成員函數(shù)。this指針存放于cx寄存器,參數(shù)從右到左壓。thiscall不是關(guān)鍵詞,因此不能被程序員指定。 5、naked call采用1-4的調(diào)用約定時(shí),如果必要的話,進(jìn)入函數(shù)時(shí)編譯器會(huì)產(chǎn)生代碼來保存esi,edi,ebx,ebp寄存器,退出函數(shù)時(shí)則產(chǎn)生代碼恢復(fù)這些寄存器的內(nèi)容。naked call不產(chǎn)生這樣的代碼。naked call不是類型修飾符,故必須和_declspec共同使用。 關(guān)鍵字 __stdcall、__cdecl和__fastcall可以直接加在要輸出的函數(shù)前,也可以在編譯環(huán)境的setting...\c/c++ \code generation項(xiàng)選擇。當(dāng)加在輸出函數(shù)前的關(guān)鍵字與編譯環(huán)境中的選擇不同時(shí),直接加在輸出函數(shù)前的關(guān)鍵字有效。它們對應(yīng)的命令行參數(shù)分別為/gz、 /gd和/gr。缺省狀態(tài)為/gd,即__cdecl。 要完全模仿pascal調(diào)用約定首先必須使用__stdcall調(diào)用約定,至于函數(shù)名修飾約定,可以通過其它方法模仿。還有一個(gè)值得一提的是winapi 宏,windows.h支持該宏,它可以將出函數(shù)翻譯成適當(dāng)?shù)恼{(diào)用約定,在win32中,它被定義為__stdcall。使用winapi宏可以創(chuàng)建自己 的apis。 2)名字修飾約定 1、修飾名(decoration name) “c”或者“c++”函數(shù)在內(nèi)部通過修飾名識(shí)別。修飾名是編譯器在編譯函數(shù)定義或者原型時(shí)生成的字符串。有些情況下使用函數(shù)的修飾名是必要的,如在模塊定義文件里頭指定輸出“c++”重載函數(shù)、構(gòu)造函數(shù)、析構(gòu)函數(shù),又如在匯編代碼里調(diào)用“c””或“c++”函數(shù)等。 修飾名由函數(shù)名、類名、調(diào)用約定、返回類型、參數(shù)等共同決定。 2、名字修飾約定隨調(diào)用約定和編譯種類(c或c++)的不同而變化。函數(shù)名修飾約定隨編譯種類和調(diào)用約定的不同而不同,下面分別說明。 a、c編譯時(shí)函數(shù)名修飾約定規(guī)則: __stdcall調(diào)用約定在輸出函數(shù)名前加上一個(gè)下劃線前綴,后面加上一個(gè)“@”符號(hào)和其參數(shù)的字節(jié)數(shù),格式為_functionname@number。 __cdecl調(diào)用約定僅在輸出函數(shù)名前加上一個(gè)下劃線前綴,格式為_functionname。 __fastcall調(diào)用約定在輸出函數(shù)名前加上一個(gè)“@”符號(hào),后面也是一個(gè)“@”符號(hào)和其參數(shù)的字節(jié)數(shù),格式為@functionname@number。 它們均不改變輸出函數(shù)名中的字符大小寫,這和pascal調(diào)用約定不同,pascal約定輸出的函數(shù)名無任何修飾且全部大寫。 b、c++編譯時(shí)函數(shù)名修飾約定規(guī)則: __stdcall調(diào)用約定: 1、以“?”標(biāo)識(shí)函數(shù)名的開始,后跟函數(shù)名; 2、函數(shù)名后面以“@@yg”標(biāo)識(shí)參數(shù)表的開始,后跟參數(shù)表; 3、參數(shù)表以代號(hào)表示: x--void , d--char, e--unsigned char, f--short, h--int, i--unsigned int, j--long, k--unsigned long, m--float, n--double, _n--bool, .... pa--表示指針,后面的代號(hào)表明指針類型,如果相同類型的指針連續(xù)出現(xiàn),以“0”代替,一個(gè)“0”代表一次重復(fù); 4、參數(shù)表的第一項(xiàng)為該函數(shù)的返回值類型,其后依次為參數(shù)的數(shù)據(jù)類型,指針標(biāo)識(shí)在其所指數(shù)據(jù)類型前; 5、參數(shù)表后以“@z”標(biāo)識(shí)整個(gè)名字的結(jié)束,如果該函數(shù)無參數(shù),則以“z”標(biāo)識(shí)結(jié)束。 其格式為“?functionname@@yg*****@z”或“?functionname@@yg*xz”,例如 int test1-----“?test1@@yghpadk@z” void test2 -----“?test2@@ygxxz” __cdecl調(diào)用約定: 規(guī)則同上面的_stdcall調(diào)用約定,只是參數(shù)表的開始標(biāo)識(shí)由上面的“@@yg”變?yōu)?span lang="EN-US">“@@ya”。 __fastcall調(diào)用約定: 規(guī)則同上面的_stdcall調(diào)用約定,只是參數(shù)表的開始標(biāo)識(shí)由上面的“@@yg”變?yōu)?span lang="EN-US">“@@yi”。 vc++對函數(shù)的省缺聲明是"__cedcl",將只能被c/c++調(diào)用. cb在輸出函數(shù)聲明時(shí)使用4種修飾符號(hào) //__cdecl cb的默認(rèn)值,它會(huì)在輸出函數(shù)名前加_,并保留此函數(shù)名不變,參數(shù)按照從右到左的順序依次傳遞給棧,也可以寫成_cdecl和cdecl形式。 //__fastcall 她修飾的函數(shù)的參數(shù)將盡肯呢感地使用寄存器來處理,其函數(shù)名前加@,參數(shù)按照從左到右的順序壓棧; //__pascal 它說明的函數(shù)名使用pascal格式的命名約定。這時(shí)函數(shù)名全部大寫。參數(shù)按照從左到右的順序壓棧; //__stdcall 使用標(biāo)準(zhǔn)約定的函數(shù)名。函數(shù)名不會(huì)改變。使用__stdcall修飾時(shí)。參數(shù)按照由右到左的順序壓棧,也可以是_stdcall;
發(fā)表者:echoher
far是古代的東西 在16位模式下,指針是16位的 指針的尋址空間只有64k 如果指定far,說明這個(gè)指針指向的地址要加上基地址 就是說用far可以指定64k以外的區(qū)域 現(xiàn)在已經(jīng)沒用了 一點(diǎn)用也沒有了
posted on 2011-01-10 13:38 肥仔 閱讀(1516) 評(píng)論(1) 編輯 收藏 引用 所屬分類: C++ 基礎(chǔ)
Powered by: C++博客 Copyright © 肥仔