必须用go tool compile -s -n -l main.go查看真实汇编,关优化与内联以确保输出原始逻辑;text行含函数入口、fp偏移布局(如a+0(fp))和栈帧大小($0-16),funcdata/pcdata不可省略,否则gc出错导致随机panic。

Go 汇编不是“看懂就行”,而是必须和 Go 运行时对齐——看错一个 FP 偏移、漏掉一条 FUNCDATA,程序可能跑半小时才 panic,堆栈里还找不到线索。
怎么用 go tool compile -S 看真实汇编输出
这是你理解 Go 函数调用约定的第一步,也是唯一可靠起点。别信手写的“类比示例”,直接看编译器生成的。
-
go tool compile -S -N -l main.go:关掉优化(-N)和内联(-l),确保看到原始逻辑 - 输出里找
TEXT main.add(SB)这类行,它告诉你函数入口、参数布局、栈帧大小(如$0-16表示无局部变量、参数+返回共 16 字节) - 注意
MOVQ a+0(FP), AX这种写法:这里的a+0(FP)不是 C 风格指针解引用,而是 Plan9 的符号偏移语法;FP是只读伪寄存器,不能做ADDQ $8, FP - 若看到
CALL runtime.morestack_noctxt,说明该函数被标记为可能分裂栈——你自己写的汇编函数若加了NOSPLIT,就绝不能调用任何 Go 函数,否则 runtime 会拒绝调度
TEXT ·add(SB), NOSPLIT, $0-16 各字段含义与常见填错
这行不是装饰,每个字段都参与链接和运行时校验。
-
·add中的·是 Unicode U+00B7(不是 ASCII.),少一个点或打成英文点号,链接时报relocation target not defined -
(SB)表示静态基址,写成(SP)或(FP)就变成访问栈上随机地址,链接能过,运行时直接 segfault -
NOSPLIT表示禁用栈分裂检查,适用于无调用、无指针逃逸的纯计算函数;若函数内部调用了runtime.printint这类函数,必须去掉NOSPLIT,否则在栈紧张时 panic -
$0-16的格式是$frame_size-args_and_results_size;$0表示无局部变量,16是输入两个int64(各 8 字节)+ 返回一个int64(8 字节)——但 Go 只预留输入+返回空间,不包含返回值实际存储(由调用方分配),所以是 16 而非 24
为什么 FUNCDATA 和 PCDATA 不能省,且顺序不能错
这不是“可选注释”,是 GC 扫描栈帧的坐标图。漏掉或写错,对象会在某次 GC 后变成悬垂指针,现象是随机 panic 或数据被覆盖。
- 只要函数签名含指针类型(如
func Copy(dst, src []byte) int),就必须在TEXT后立即写:FUNCDATA $0, gclocals·add(SB)PCDATA $0, $0 -
gclocals·add(SB)必须在同包 Go 文件中用var gclocals·add = ...定义,内容是编译器生成的字节序列(通常从go tool compile -S输出里复制) -
FUNCDATA $0对应栈上指针映射表,PCDATA $0对应 PC 偏移到该映射表的索引;二者顺序颠倒或缺失其一,GC 会读错偏移,把整数当指针扫,或跳过真实指针 - 没有指针参数/返回值、且无局部指针变量的函数(如纯
int64运算),可省略这两条——但一旦加了 slice、map、interface{},就必须补全
DATA 和 GLOBL 的顺序、标志与 GC 风险
全局变量定义不是“先声明再赋值”,而是严格按内存段语义分步操作。
- 必须先
DATA再GLOBL:前者写入初始值,后者宣告符号全局可见并指定大小/属性;反序会导致链接器忽略DATA,变量值为全零 -
GLOBL ·Id(SB), NOPTR, $8中NOPTR表示该变量不含指针,GC 会跳过扫描;若误用于[]byte类型变量,GC 可能提前回收底层数组 - 只读数据(如字符串常量)优先用
RODATA标志:GLOBL ·msg(SB), RODATA, $12;它隐式带NOPTR,且加载到只读段,运行时写入会触发 segfault,反而帮你早发现问题 -
DATA ·Id+0(SB)/1, $0x37的/1表示写入 1 字节,后续+1、+2必须严格递增,中间不能跳(如+0后直接+2),否则未覆盖区域为零,可能破坏结构体对齐
最易被忽略的其实是“跨平台一致性”:同一份逻辑,amd64 下 FP 偏移有效,换到 arm64 就得重算——Plan9 汇编不是写一次到处跑,每个 GOARCH 都要单独文件、单独验证。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











