不调用具有"协程特性"的系统API函数而使用汇编实现协程

来源:互联网 发布:网络上说表妹什么意思 编辑:程序博客网 时间:2024/05/23 11:28

上一篇根据云风的协程库实现了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):

    共享栈是时间换空间,所有协程都共享一个公共栈,当协程较多时大大的节约了内存,但是由于共享,所以栈数据的拷贝将大大降低效率,不过共享栈可以

让调用者不用担心协程栈的大小问题,基本不用担心栈爆掉的现象。

    非共享栈是空间换时间,每个协程都有自己独有的栈

可以根据具体的场景决定使用共享栈还是非共享栈。


0 0
原创粉丝点击