常见错误与排障(Troubleshooting)
按"汇编 → 链接 → 运行"三个阶段收录常见报错与对策。报错原文以 GNU binutils 为准(不同版本措辞略有差异,关键是识别模式)。
汇编阶段(as)
| 报错(模式) |
原因 |
对策 |
no instruction mnemonic suffix given and no register operands; using default(警告) |
指令涉及内存/立即数但没写大小后缀,GAS 套用默认 32 位 |
显式写后缀:movl $1, (%rax) 而非 mov $1, (%rax) |
operand size mismatch |
操作数大小不匹配(含内存↔内存这种非法组合) |
检查后缀;内存到内存必须经寄存器中转 |
bad register name |
寄存器名写错,或混入了中文标点(如 %eax;) |
检查全角符号,代码只用 ASCII 标点 |
no such instruction |
拼写错误,或指令属于未开启的扩展 |
查模块十七;用 gcc -mavx2 -c 等开启扩展 |
unknown pseudo-op |
伪指令拼写错误或版本不支持 |
核对伪指令表(模块二) |
junk at end of line |
行尾有多余内容(多余的逗号/操作数) |
检查操作数个数与分隔 |
expecting operand |
缺少操作数 |
补全 |
no such architecture |
.arch 值不受支持(x86 64 位模式支持有限) |
改用 gcc 的 -m 选项,见模块二 |
undefined symbol / 标号未定义 |
引用了不存在的标号 |
检查标号拼写、1f/1b 方向、跨文件引用需 .globl |
cannot represent relocation / 立即数超范围 |
立即数超过 32 位(非 mov) |
用 movabsq 或寄存器中转 |
链接阶段(ld / gcc 链接)
| 报错(模式) |
原因 |
对策 |
undefined reference to 'foo' |
符号在目标文件/库中不存在 |
检查 .globl 声明、拼写、是否忘了把 .o 传给链接器 |
relocation truncated to fit: R_X86_64_32S |
32 位符号扩展位移放不下(符号距离/地址超出 ±2GB) |
改用 RIP 相对寻址、movabsq+寄存器间接、或调整代码布局 |
missing .note.GNU-stack section implies executable stack(警告) |
汇编源没有栈权限标记 |
加 .section .note.GNU-stack,"",@progbits(模块二) |
无法找到项目符号 _start(警告,缺省入口 0x401000) |
没有定义 _start,链接器随便指了个入口——程序基本无法运行 |
定义 _start 或用 ld -e 入口名 |
链接 libc 时报 undefined reference to 'printf' |
用裸 ld 链接却调用了 libc |
改用 gcc 驱动 链接,或手动 -lc + 动态链接器路径 |
运行阶段
| 症状 |
常见原因 |
排查 |
| Segmentation fault |
入口错误、参数寄存器搞错、忘了 lea(把数据当指针)、callee-saved 未保存、栈未对齐后用了 movaps |
gdb → run → bt → x/i $pc 定位(模块十四) |
| Illegal instruction (SIGILL) |
使用了 CPU 不支持的指令 / OS 未启用 XCR0 状态 |
模块十五 的检测流程 |
| SIGBUS |
错对齐的内存访问(如 movaps 访问非 16 字节对齐地址) |
检查 .align/.p2align(模块十) |
| SIGFPE |
整数除零(div/idiv 除数为 0,或商溢出) |
检查除数寄存器是否被清错 |
| 程序"什么都没干"就退出 |
退出码只取低 8 位;或没有 exit 直接跑了 .text 后面的数据 |
检查退出路径(模块七) |
| 结果莫名被改动 |
子寄存器写规则(写 32 位清高 32 位)、%rdx 除法残留 |
见模块一、模块四 |
快速定位流程图
汇编不通过 ──► 按 as 报错行号查上表
链接不通过 ──► undefined reference → 查符号/globl
└► relocation truncated → 查寻址方式
运行崩溃 ──► gdb ./prog
run
bt # 看调用栈
x/i $pc # 看崩溃指令
info registers # 看寄存器值
strace ./prog # 看最后做了什么系统调用
配套工具一览
| 工具 |
用途 |
as -a |
列出汇编清单(源码+机器码对照) |
objdump -dr |
反汇编 + 重定位信息(查 relocation 问题) |
readelf -hS / readelf -s |
ELF 节区 / 符号表 |
nm |
快速查看符号定义与缺失 |
strace |
跟踪系统调用与信号 |
gdb |
寄存器/内存/单步(模块十四);core dump、反向调试、多线程等进阶见模块十九 |
更多防错要点见总览的"常见陷阱"一节。