Jacky's blog
首页
  • Android
  • Web
  • Server
  • Python
  • iOS
  • Java
  • Vue
  • 计算机基础
  • 工具链
  • AI
  • 个人成长
  • 博客
  • 分类
  • 标签
  • 归档
收藏
GitHub (opens new window)

Jack Yang

编程; 随笔
首页
  • Android
  • Web
  • Server
  • Python
  • iOS
  • Java
  • Vue
  • 计算机基础
  • 工具链
  • AI
  • 个人成长
  • 博客
  • 分类
  • 标签
  • 归档
收藏
GitHub (opens new window)
  • 开发工具

  • 构建工具

  • 版本控制

  • 容器

  • 调试工具

    • lldb
    • nm - 查看二进制符号表
      • 1. 核心概念
        • 1.1 什么是符号
        • 1.2 符号类型字母(最重要)
      • 2. 常用命令
        • 2.1 基本用法
        • 2.2 iOS / macOS 常用
        • 2.3 完整选项速查
      • 3. 实际场景
        • 3.1 链接报错:undefined symbol
        • 3.2 查 Framework 导出了什么
        • 3.3 Swift 符号 demangle
        • 3.4 对比两个版本的符号差异
        • 3.5 查私有 API / 隐藏符号
      • 4. 与相关工具配合
      • 5. 常见问题
        • 5.1 输出太多怎么办
        • 5.2 Fat Binary 多架构
        • 5.3 静态库 vs 动态库
      • 6. 速查
    • jadx
  • 测试工具

  • CLI 工具

  • 网络工具

  • 编辑器

  • 设计工具

  • 多媒体

  • 包管理

  • 平台工具

  • tools
  • debug_tools
Jacky
2026-09-12
目录

nm - 查看二进制符号表

nm(name list)用于列出目标文件、静态库、动态库和可执行文件中的符号表。 理解符号类型字母是用好 nm 的关键。

# 1. 核心概念

# 1.1 什么是符号

编译器把源码编译成机器码后,函数名、全局变量名等在二进制里以**符号(symbol)**形式存在。nm 就是查看这些符号的工具。

源码: int g_value = 42;
二进制符号:
0000000100004010 D _g_value
1
2
3

# 1.2 符号类型字母(最重要)

nm 输出第二列是一个字母,表示符号类型。大小写有含义:大写 = 外部(外部可见/已定义),小写 = 内部(局部/私有)。

字母 含义 说明
U Undefined 未定义——本文件引用但未实现,需要从其他库链接
T / t Text 代码段(函数),大写外部可见,小写内部私有
D / d Data 已初始化全局/静态变量,大写外部,小写内部
B / b BSS 未初始化全局/静态变量,运行时自动清零
S / s Static 特殊静态数据(如 dyld 私有段)
A / a Absolute 绝对符号(值不随链接改变)
C Common 公共符号( tentative 定义,未分配空间)
I Indirect 间接符号(stub,指向另一个符号)
N Debugging 符号
R / r Read-only 只读数据(如字符串常量)
V / v Weak Weak 符号(可被同名强符号覆盖)
W / w Weak 另一种 Weak 符号(未定义 weak)
- stabs 调试符号

记忆口诀:

  • U = 有引用无实现(undefined)
  • T = 函数(text/code)
  • D/B = 变量(已初始化/未初始化)
  • 大写 = 外部可见,小写 = 文件私有

# 2. 常用命令

# 2.1 基本用法

# 列出文件中所有符号
nm <binary>

# 只看 undefined 符号(找未链接的依赖)
nm -u <binary>

# 只看已定义符号
nm -j <binary>          # 只输出符号名,不带地址和类型

# 按符号名排序
nm -n <binary>          # 按地址排序
nm -p <binary>          # 不排序(保持文件顺序)

# 反向(不区分大小写)
nm -g <binary>          # 只看外部(global)符号
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 2.2 iOS / macOS 常用

# 查看动态库导出了哪些符号
nm -gU /path/to/framework/Framework
#   -g: 只看外部符号
#   -U: 不显示 undefined(即只看已导出的)

# 查看可执行文件引用了哪些外部符号
nm -u /path/to/executable

# 查看某个类/方法的符号(Objective-C)
nm <binary> | grep -i "ViewController"

# Swift 符号 mangled 后很长,需要 demangle
nm <binary> | grep "ViewController" | swift demangle

# 批量 demangle
nm <binary> | swift demangle
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 2.3 完整选项速查

选项 作用
-a 显示所有符号,包括调试符号
-g 只显示外部(global)符号
-u 只显示未定义符号(undefined)
-U 只显示已定义符号
-j 只输出符号名
-n 按地址数值排序
-p 不排序
-r 逆序
-l 显示行号(需要调试信息)
-arch <arch> 指定架构(如 arm64)
-f 显示 fat binary 的所有架构
-m 输出 Mach-O 风格信息

# 3. 实际场景

# 3.1 链接报错:undefined symbol

编译时遇到 Undefined symbols for architecture arm64::

# 看可执行文件缺哪些符号
nm -u MyApp | grep <缺失符号名>

# 确认某个库是否导出了这个符号
nm -gU libSomeLib.a | grep <符号名>
1
2
3
4
5

# 3.2 查 Framework 导出了什么

nm -gU MyFramework.framework/MyFramework
1

输出示例:

0000000000003a40 T _$s11MyFramework0A5ClassC0A10MethodyyF
0000000000003b20 S _OBJC_CLASS_$_MyFramework
1
2

# 3.3 Swift 符号 demangle

Swift 编译后的符号是 mangled 的($s...),直接看很难懂:

# 方法1:管道
nm MyBinary | grep "MyClass" | swift demangle

# 方法2:直接 demangle
xcrun swift-demangle < mangled_symbol
1
2
3
4
5

mangled: $s11MyFramework0A5ClassC0A10MethodyyF demangled: MyFramework.MyClass.method() -> ()

# 3.4 对比两个版本的符号差异

# 导出符号列表
nm -gU old.app/MyApp > old_symbols.txt
nm -gU new.app/MyApp > new_symbols.txt

# 对比
diff old_symbols.txt new_symbols.txt
1
2
3
4
5
6

# 3.5 查私有 API / 隐藏符号

# 查看系统 Framework 的所有符号(包括私有的)
nm /System/Library/Frameworks/UIKit.framework/UIKit

# 找某个类的所有方法
nm -gU UIKit | grep -i "PrivateClass"
1
2
3
4
5

# 4. 与相关工具配合

工具 用途 配合 nm
otool -L 查看链接的动态库 nm -u 看缺什么符号,otool -L 看依赖哪些库
strings 提取字符串 nm 找符号,strings 找硬编码文本
lldb 动态调试 nm 找符号地址,lldb 在该地址下断点
swift-demangle Swift 符号反混淆 nm 输出管道给 swift-demangle
objdump 反汇编 nm 定位符号,objdump -d 反汇编该符号

# 5. 常见问题

# 5.1 输出太多怎么办

# 只看外部已定义符号(过滤掉大量内部符号)
nm -gU <binary> | wc -l

# grep 过滤
nm <binary> | grep "T _" | grep "ViewController"
1
2
3
4
5

# 5.2 Fat Binary 多架构

# 查看所有架构
nm -f <binary>

# 指定 arm64
nm -arch arm64 <binary>
1
2
3
4
5

# 5.3 静态库 vs 动态库

  • 静态库(.a):nm lib.a 会列出每个目标文件的符号,可能有大量重复
  • 动态库(.dylib/.framework):nm 直接看导出/导入表

# 6. 速查

# 我想知道这个文件导出了什么
nm -gU <binary>

# 我想知道缺什么符号
nm -u <binary>

# 我想找某个函数
nm <binary> | grep "funcName"

# Swift 符号看不懂
nm <binary> | swift demangle

# 对比两个版本
diff <(nm -gU old) <(nm -gU new)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#tool#reverse#symbol
上次更新: 2026/10/09, 15:51:11
lldb
jadx

← lldb jadx→

最近更新
01
GitHub CLI(gh)工作流与 CI 排查
10-08
02
Xcode 工程文件说明
09-28
03
osascript
09-23
更多文章>
Theme by Vdoing | Copyright © 2019-2026 Jacky | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式