Go查看汇编有三种可靠方式:用go tool compile -S看Plan 9伪汇编(含源码行号)、用go tool objdump反汇编真实二进制(需关优化)、用lensm实现源码-汇编实时映射。

Go 编译器不生成可直接汇编的 AT&T 或 Intel 语法文件,所谓“查看汇编”只有三种可靠路径:看编译器中间输出(go tool compile -S)、反汇编最终二进制(go tool objdump)、或用 lensm 做源码-汇编映射。其他方式要么无效,要么看到的是假信息。
用 go tool compile -S 看编译器生成的 Plan 9 汇编
这是最常用、最轻量的方式,输出的是 Go 编译器 SSA 后端生成的伪汇编,带源码行号和变量名,适合调试和理解优化行为。
-
-S必须小写;加两次(-S -S)会显示更底层的 SSA 阶段指令 - 遇到
import报错?别用go tool compile单文件执行,改用:go build -gcflags="-S" -o /dev/null main.go - 想只看某个函数?
go build -gcflags="-S" main.go 2>&1 | grep -A20 "main\.Add$"(注意点号要转义) - 输出里出现
CALL runtime.morestack_noctxt或CALL runtime.newobject,说明触发了栈分裂或堆分配——不是汇编写错了,是代码本身有逃逸或扩容
用 go tool objdump 反汇编真实二进制
这是验证“最终跑起来的是不是你写的汇编”的唯一办法。但默认构建下,函数常被内联或优化掉,objdump 扫不到。
- 先关优化:
go build -gcflags="-l -N" -o myapp main.go(-l禁内联,-N禁优化) - 确认符号存在:
go tool nm ./myapp | grep "main\.Add";Windows 下符号是main·Add,Linux/macOS 是main.Add - 精准反汇编:
go tool objdump -s "main.Add" ./myapp(函数名必须带包路径,且按平台转义) - 如果输出全是
CALL runtime.*而没有你的MOVQ/ADDQ,说明汇编没接入——回去检查.s文件名、·Add(SB)中的中点、Go 函数签名三者是否完全一致
用 lensm 实现源码与汇编实时映射
它把 objdump 和源码并排展示,鼠标悬停汇编行就能高亮对应 Go 行,对性能分析比纯命令行直观得多。
立即学习“go语言免费学习笔记(深入)”;
- 安装:
git clone https://gitcode.com/gh_mirrors/le/lensm && cd lensm && go build -o lensm ./lensm - 运行:
./lensm -filter "Add" ./myapp(-filter快速定位函数) - 它自动处理符号名差异(比如
main.Add·f这类后缀),不用手动从nm复制全名 - 注意:
lensm依赖二进制里的调试信息,所以构建时别加-ldflags="-s -w",否则映射失效
真正难的不是贴出几条指令,而是确保每处偏移、每个伪寄存器、每次调用约定都对得上——FP 不是栈顶,SP 不是参数起点,· 不是 .,$0-16 不等于两个 int64 加一个 int64 的字节和。错一个,程序可能跑通,但结果随机。


















