上一篇根據雲風的協程庫實現了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):
共享棧是時間換空間,所有協程都共享一個公共棧,當協程較多時大大的節約了內存,但是由於共享,所以棧數據的拷貝將大大降低效率,不過共享棧可以
讓調用者不用擔心協程棧的大小問題,基本不用擔心棧爆掉的現象。
非共享棧是空間換時間,每個協程都有自己獨有的棧
可以根據具體的場景決定使用共享棧還是非共享棧。