Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

想问一下为什么这里要将函数返回地址保存起来呢? #91

Closed
asdf1352 opened this issue Jul 2, 2018 · 6 comments
Closed

Comments

@asdf1352
Copy link

asdf1352 commented Jul 2, 2018

pushl %eax //set ret func addr

对这一处不太明白,既然每一个协程都有自己的栈帧,函数返回地址又是保存在栈帧中的,不同于共享的寄存器,栈是相互独立的,为什么这里还要把返回地址压栈?,比如说我考虑成
`

#if defined(i386)
leal %esp, %eax //sp
movl 4(%esp), %esp
leal 32(%esp), %esp //parm a : &regs[7] + sizeof(void*)

pushl %eax //esp ->parm a 

pushl %ebp
pushl %esi
pushl %edi
pushl %edx
pushl %ecx
pushl %ebx



movl 8(%eax), %esp //parm b -> &regs[0]


popl %ebx  
popl %ecx
popl %edx
popl %edi
popl %esi
popl %ebp
popl %esp

xorl %eax, %eax
ret

`
这样会有什么问题呢?

@hnes
Copy link

hnes commented Jul 2, 2018

当然可以这样做,你甚至可以将所有寄存器统统保存在栈帧上,只要注意好细节处理就可以。

不过我没有仔细看你的汇编代码,不能保证里面细节没有问题。

另外需要注意的是,SP是不应该用来直接寻址堆中的数据结构的。(原因请参加bug报告 issue 90

如果你想要实现自己的协程,建议参考libacoacosw(更快速且正确的)实现,腾讯的这个coctx_swap里面有bug而且效率低,更关键的是现在他们对这个项目似乎一点也不关心了。

@hnes
Copy link

hnes commented Jul 2, 2018

libaco的README文档包含了完整的协程实现的方法论和严格的数学证明,如果你不喜欢读英文的话,它的中文文档过几天就会放出来。

另外,boost的context库的协程实现也很棒,它就是把所有寄存器的状态统统保存在栈帧上,如果感兴趣的话你也可以看一下。

@asdf1352
Copy link
Author

asdf1352 commented Jul 2, 2018

@hnes 谢谢答复,其实主要比较疑惑的就是函数返回地址本身就作为栈帧的一部分,却特意将其保存起来之后再恢复这个行为不太能理解,也谢谢您的推荐,最近在研究协程,会仔细阅读下您的代码和资料

@hnes
Copy link

hnes commented Jul 2, 2018

@asdf1352 不用客气,有问题的话欢迎继续交流 :)

@yuanzhubi
Copy link

libco需要实现拷贝栈,然而在协程切换之前,需要拷贝保存的内容到底有多长是不知道的。所以必须在栈切换的时候保存好栈指针前面的所有内容。

@asdf1352
Copy link
Author

@yuanzhubi 原来如此,只在看独立栈没看拷贝栈的情况,谢谢大佬

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants