不調用具有"協程特性"的系統API函數而使用匯編實現協程

上一篇根據雲風的協程庫實現了windows下的協程:fiber協程


今天,打算用匯編實現一下(windows下彙編),實現之前需要先複習下函數調用的基礎:點擊打開鏈接             點擊打開鏈接2    點擊打開鏈接3

每個函數都有自己的堆棧,一般函數開頭都有類似的語句:push ebp;mov ebp,esp;且函數調用前會將eip入棧,

以使函數能夠正確返回.即可回到函數入口處繼續往下執行,因此保存上下文信息(寄存器信息),獲取當前程序(函數)

運行完成後怎麼返回是我們實現的關鍵,亦即獲取eip信息併入棧是我們實現的關鍵.需要清楚的是,eip入棧後才進行上下文的保存.


一個函數大概的流程: 將函數需返回指令地址入棧  -> 保存ebp等寄存器信息 -> 函數運行 -> 將ebp等數據出棧 -> 將指令地址出棧到eip中

程序根據eip信息繼續執行!!



用匯編實現最好採用C調用匯編函數的方式調用,彙編代碼保存在.S文件中,可參考libco開源庫,如果採用C函數嵌入彙編的方式,則可能

會出現問題,因爲debug模式/release模式或release優化模式生成的彙編都不同,可能導致不能準確的獲取到 指令地址!!! 後來經過大神引導

才知道有裸函數這種用法。普通嵌入彙編:

A:

void test(){

   __asm{

    ...

}

}

A調用方法,會在進入彙編之前做一些上下文的保存,使我們獲取 指令地址不太方便,因爲我們不知道中間堆棧有多少變化!!

裸函數嵌入彙編:

B:

__declspec(naked) void __cdecl test(){

   __asm{

    ...

}

}

B調用方法,不會生成多餘的彙編,需要我們手動對上下文進行保存,因此,我們很清除的知道堆棧變化,從而方便獲取指令地址!!!

需要注意的是本人使用的VS2013,配置管理配置的Win32,所以沒問題,如果改成X64,不但不支持__asm{}這種用法,也不可

使用naked這樣的裸函數用法,所以,還是可以把彙編單獨成彙編文件供C/C++調用.x86平臺轉x64平臺關於內聯彙編不再支持的解決

VS2012下X64平臺嵌入彙編程序    VS2010中編寫x64彙編的具體方法 ,上面的方法都是通過彙編生成**.obj文件,然後一起鏈接生成

最後需要的文件。據說還可以用asmjit(google的一個即時編譯器庫)或 shellcode。

shellcode使用實例如下:

UCHAR ShellCode[] = {機器碼};
typedef (type)(*funptr)(...);
funptr f = (funptr)ShellCode;
f();


共享棧和非共享棧協程(stackful/stackless):

    共享棧是時間換空間,所有協程都共享一個公共棧,當協程較多時大大的節約了內存,但是由於共享,所以棧數據的拷貝將大大降低效率,不過共享棧可以

讓調用者不用擔心協程棧的大小問題,基本不用擔心棧爆掉的現象。

    非共享棧是空間換時間,每個協程都有自己獨有的棧

可以根據具體的場景決定使用共享棧還是非共享棧。


發佈了67 篇原創文章 · 獲贊 19 · 訪問量 27萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章