主要观点:最近作者诊断并修复了 Go 中的两个帧指针展开崩溃问题,原因是错误的汇编代码破坏了帧指针,包括破坏寄存器和栈上的值,文章解释了这些问题,讨论了 ABIs 和调用约定,并给出避免问题的建议。
关键信息:
- 第一个问题是升级到 Go 1.23 并使用配置文件引导优化(PGO)后,块分析器在程序加载时崩溃,关键线索是错误内存访问的地址,发现受影响的程序使用了
github.com/dgryski/go-metro库中的有问题的汇编代码,其中MOVQ AX, BP指令破坏了帧指针寄存器BP。 - 第二个问题是在 Datadog 中发现的一个程序崩溃,原因是
memory_memset_neon函数在 ARM64 上错误地保存了帧指针,导致异步抢占和执行跟踪时崩溃,作者报告并修复了该问题,意识到可以通过给函数一个非零帧大小让汇编器插入帧指针保存和恢复代码。 - 汇编级代码的规则属于“应用二进制接口”(ABI),Go 程序员应参考 Go 汇编指南和内部 ABI 指南,可借助 Avo 等工具处理细节。
重要细节: - PeachPy 生成的
go-metro仓库中的汇编代码存在问题,Avo 知道要保存帧指针寄存器且目前支持 Go 汇编,go vet的检查会遗漏此类问题已提交 issue 跟踪改进。 - ARM64 上 Go 编译器将调用者的帧指针保存在函数栈帧下方一个字的位置,而 AMD64 则不同。
- 有时函数调用下方的空间被称为“红区”。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用。你还可以使用@来通知其他用户。