什么是 上下文注册 ?它如何改变Go代码的编译方式?
上下文:我在GOROOT的某些部分看到了存根函数的使用,即reflect
,但我不太确定它们是如何工作的。
答案 0 :(得分:5)
表达式"上下文寄存器"首次出现在commit b1b67a3(2013年2月,Go 1.1rc2)中,以实现Go 1.1 Function Calls
的第3步更改
reflect.MakeFunc
实施以避免运行时代码生成
2014年2月在commit 4a000b9中获取了Go 1.3beta1,用于Native Client x86-64的汇编和系统调用,其中sigreturn is managed as:
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,commit d5bd797我们有commit bf9c71c和eliminating stack rescanning:
morestack
将上下文指针写入gobuf.ctxt
,但是从那以后morestack
是用汇编语言编写的(并且必须非常小心 它确实不为此调用必要的写屏障 写。相反,我们稍后会在我们调用的newstack
中对其进行修补 ctxt的显式写屏障。这已经需要一些微妙的推理,并且它会得到一个 混合屏障很多毛发。
通过简化整个机制来解决这个问题 而不是在
gobuf.ctxt
中写morestack
,只需将上下文寄存器的值传递给newstack
,然后将其写入gobuf.ctxt
。这是一个正常的Go指针写入,因此它获得了正常的Go写屏障。不需要微妙的推理。