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

NO IMAGE

上一篇根據雲風的協程庫實現了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):

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

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

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

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