表达"上下文寄存器"首次出现在提交b1b67a3(2013年2月,Go 1.1rc2)中,用于实现Go 1.1函数调用的第3步
更改
reflect.MakeFunc
实现以避免运行时代码生成
它在2014年2月的提交4a000b9中获取,转到1.3beta1,用于Native Client x86-64的汇编和系统调用,其中sigreturn管理为:
NaCl
已经消除了其传统的操作系统责任,并拒绝执行'sigreturn
'.
相反,返回执行程序的唯一方法是自己恢复寄存器.不幸的是,严格的保真度是不可能做到的,因为没有任何方法可以对PC的最终更新结束序列
- (1)跳转到寄存器,在这种情况下寄存器结束保持PC值而不是其预期值,或
- (2)存储
PC
在堆栈上并使用RET
,它强加了SP
有效的要求,并且可以粉碎它下面的单词.第二个通常是两个邪恶中的较小者,除了在NaCl上,链接器必须重写
RET
为"POP reg; AND $~31, reg; JMP reg
",所以无论哪种方式,我们将因输入信号而丢失寄存器.同样,没有办法恢复
EFLAGS
; 通常的方法是使用POPFL
,但NaCl
拒绝该指令.
我们可以检查这些位并执行一系列旨在重新创建这些标志设置的指令,但这需要做很多工作.值得庆幸的是,Go的信号处理程序永远不会尝试直接返回执行代码,所以所有的寄存器
EFLAGS
都已经死了,可以被粉碎.
唯一重要的寄存器是为信号处理程序创建的模拟调用设置的寄存器.
今天这些寄存器只是PC
和SP
,但如果将来有其他寄存器相关(例如DX
Go funccontext register
),我们会尽可能多地恢复寄存器.
最近(2016年第4季度),对于Go 1.8,我们提交d5bd797并提交bf9c71c,以消除堆栈重新扫描:
morestack
写上下文指针gobuf.ctxt
,但由于morestack
是用汇编(并且要非常小心的状态),它并没有调用此写入所需的写屏障.相反,我们稍后会修补它,在newstack
那里我们调用ctxt的显式写屏障.这已经需要一些微妙的推理,并且混合屏障会变得更加毛茸茸.
通过简化整个机制来解决这个问题.
而不是写的gobuf.ctxt
在morestack
,只是通过上下文寄存器的值newstack
,让它把它写入gobuf.ctxt
.这是一个正常的Go指针写入,因此它获得了正常的Go写屏障.不需要微妙的推理.