当前位置: 首页 > news >正文

五分钟系列-nm工具

目录

1. nm 工具是什么?

2. 为什么需要 nm?主要用途

3. 基本语法和输出格式

基本语法

输出格式

4. 重要的符号类型(Symbol Types)

5. 常用选项和示例

示例代码 (test.c)

1. 默认输出(列出所有符号)

2. 只显示未定义的符号 (-u)

3. 只显示已定义的符号 (--defined-only)

4. 按符号值排序 (-n)

5. 显示调试符号 (-a)

6. 显示外部/动态符号 (--extern-only)

7. 用于动态库 (.so)

8. 与 grep 组合使用(非常实用)

6. 注意事项和局限性

总结


1. nm 工具是什么?

nmName List​ 的缩写)是 GNU Binutils 工具集中的一个命令行程序,用于显示目标文件​(如库文件 .a.so和可执行文件)中的符号信息。

所谓符号,通常包括:

  • 函数名

  • 全局变量名

  • 静态变量名

  • 以及其他一些在链接和调试过程中至关重要的标识符。

简单来说,nm可以让你“窥探”一个二进制文件内部,看看它定义了哪些函数和变量,又引用了哪些外部的函数和变量。这对于调试链接错误排查反向工程来说极其有用。


2. 为什么需要 nm?主要用途

  1. 排查链接错误​:这是最常见的用途。当链接器报错说 undefined reference to 'function_name'时,你可以用 nm来检查:

    • 你的目标文件(.o)是否真的引用了这个符号(会标记为 U)。

    • 你链接的库文件(.a.so)是否真的定义了这个符号(应该标记为 TD等)。

  2. 分析库文件内容​:你想知道一个静态库(.a)或动态库(.so)提供了哪些函数接口,就可以用 nm来查看。

  3. 解决符号冲突​:当出现“多重定义”错误时,nm可以帮助你找到多个定义了相同符号的文件。

  4. 逆向工程与调试​:在缺乏源代码的情况下,分析二进制文件的结构,了解程序大致的执行流程。


3. 基本语法和输出格式

基本语法
nm [选项] <文件名>
输出格式

默认情况下,nm的输出通常包含三列:

<符号值> <符号类型> <符号名称>
  • 符号值​:通常是符号在内存或段中的地址偏移量。对于未定义的符号,该值为空。

  • 符号类型​:一个关键的字母,说明了符号的类型和属性(详见下文)。

  • 符号名称​:符号本身的名称。


4. 重要的符号类型(Symbol Types)

nm输出的符号类型是理解其功能的核心。以下是一些最常见和重要的类型:

类型字母

含义

示例/说明

A

绝对地址​ - 该符号的值是绝对的,在链接过程中不会被改变。

通常用于特殊用途的符号。

B

BSS 段​ - 该符号位于未初始化的数据段(BSS)中。

例如未初始化的全局变量 static int x;

D

数据段​ - 该符号位于已初始化的数据段中。

例如已初始化的全局变量 int y = 10;

T

文本段​ - 该符号位于代码段(text)中。

这是最常见的函数符号。例如函数 void func() {...}

U

未定义​ - 该符号在当前文件中被引用,但未被定义。

需要从其他库或目标文件中链接进来。这是链接错误排查的关键。

W

弱引用​ - 一个未定义的弱符号。如果找不到定义,不会导致链接错误。

常用于可选的扩展功能。

R

只读数据段​ - 该符号位于只读数据段中。

例如字符串常量 const char* str = "hello";

C

公共段​ - 该符号是公共的,未初始化的数据。

类似于 B,但行为略有不同。

I

间接引用​ - 另一个符号的间接引用(常见于动态链接)。

N

调试符号​ - 这是一个调试符号。

V

弱对象​ - 一个弱的已定义符号(弱定义)。

​-

stabs​ 符号 - 用于调试的符号信息。

​?​

未知​ - 符号类型未知,或者格式无法识别。

有时出现在特殊格式的文件中。

注意​:字母的大小写有时也表示不同的含义:

  • 小写​:符号是局部的(local),其作用域仅限于当前目标文件。

  • 大写​:符号是全局的(global/external),可以被其他目标文件使用。

例如:

  • T:全局函数

  • t:静态函数(文件内部函数)

  • D:全局变量

  • d:静态变量


5. 常用选项和示例

假设我们有一个简单的 C 程序,编译成目标文件 test.o

示例代码 (test.c)
#include <stdio.h>int global_var = 10; // 已初始化全局变量 (D)
static int static_var; // 未初始化静态变量 (B)
const int read_only_var = 100; // 只读变量 (R)void my_function() { // 全局函数 (T)static int inside_static; // 静态局部变量 (b/d, 位于BSS段)printf("Hello\n");
}void undefined_function(); // 声明一个未定义的函数int main() { // 全局函数 (T)my_function();undefined_function(); // 引用一个未定义的函数 (U)return 0;
}

使用 gcc -c test.c编译生成 test.o

1. 默认输出(列出所有符号)
nm test.o

输出可能如下(地址和顺序可能不同):

0000000000000000 T main
0000000000000000 T my_functionU printfU undefined_function
0000000000000000 D global_var
0000000000000004 R read_only_var
0000000000000000 B static_var

可以看到 printfundefined_functionU(未定义),mainmy_functionT(代码),global_varD(数据),等等。

2. 只显示未定义的符号 (-u)

用于快速检查缺少哪些依赖。

nm -u test.o

输出:

U printf
U undefined_function
3. 只显示已定义的符号 (--defined-only)
nm --defined-only test.o
4. 按符号值排序 (-n)

按地址顺序显示,对于分析内存布局很有用。

nm -n test.o
5. 显示调试符号 (-a)

通常会显示更多信息,包括调试用的符号。

nm -a test.o
6. 显示外部/动态符号 (--extern-only)

通常只显示大写类型的符号(全局符号)。

nm --extern-only test.o
7. 用于动态库 (.so)

用法完全相同。

nm /lib/x86_64-linux-gnu/libc.so.6 | head -20 # 查看glibc的前20个符号
8. 与 grep 组合使用(非常实用)

查找是否定义了某个特定函数:

nm test.o | grep main

查找所有未定义的函数:

nm test.o | grep ' U '

6. 注意事项和局限性

  1. 剥离的二进制文件​:如果可执行文件或库被 strip工具处理过(去除了符号表),nm的输出会大大减少,甚至显示 nm: testfile: no symbols。这在发布版本中很常见。

  2. C++ 名称修饰​:对于 C++ 代码,函数名会被“修饰”,包含命名空间、类、参数类型等信息,导致 nm输出的符号名难以阅读。可以使用 -C--demangle选项来将其还原为可读形式。

    nm -C my_cpp_program
  3. 不同平台​:nm主要用于 ELF 格式的文件(Linux 的标准格式),虽然它也支持其他格式,但行为和输出可能不同。

总结

nm是 Linux 开发者和系统管理员工具箱中一个不可或缺的、简单而强大的工具。它通过揭示二进制文件内部的符号信息,为调试链接问题排查二进制分析提供了关键的洞察力。掌握 nm的基本用法和符号类型含义,能极大地提高解决底层编译和链接问题的效率。

http://www.dtcms.com/a/392868.html

相关文章:

  • 【龙泽科技】新能源汽车空调系统结构原理仿真教学软件
  • 设计一个图片上传服务,支持每秒5000张图片上传,并且要实时生成多种尺寸的缩略图。你觉得架构设计的要点有哪些?
  • NLP:Transformer优势详解
  • 基于SpringBoot+Vue的民宿管理系统(WebSocket及时通讯、腾讯地图API、支付宝沙盒支付、ECharts图形化分析)
  • Git版本管理工具入门及常用命令讲解---小白版
  • 芯脉:面向高速接口的SoC架构与完整性设计<2-2>
  • Go基础:Go语言流程控制详解
  • 【硬件-笔试面试题-103】硬件/电子工程师,笔试面试题(知识点:项目当中无人机的控制是怎么实现的)
  • 融智学的信息科学与智能科学(信智科学)基础研究
  • PyTorch 容器类详解:nn.Sequential、nn.ModuleList 与 nn.ModuleDict
  • 基于规则的专家系统对自然语言处理深层语义分析的影响与启示综合研究报告
  • 微服务配置管理
  • WinDivert学习文档之五-————编程API(七)
  • 【StarRocks】-- 异步物化视图实战
  • 应用随机过程(一)
  • 【项目实战 Day4】springboot + vue 苍穹外卖系统(套餐模块 完结)
  • 素材库网站分享
  • 第8节-PostgreSQL数据类型-Text
  • React-router和Vue-router底层实现原理
  • 宝藏音乐下载站,免费好用
  • pygame AI snake 大乱斗
  • TCP FIN,TCP RST
  • 睡眠PSG统一数据集的设计思路
  • 告别Vibe Coding!敏捷AI驱动开发:用AI高效构建可维护的复杂项目
  • EA-LSS:边缘感知 Lift-splat-shot 框架用于三维鸟瞰视角目标检测
  • 和为 K 的子数组
  • 从流量红利到运营核心:“开源AI智能名片+链动2+1模式+S2B2C商城小程序”驱动电商行业价值重构
  • 【ICLR 2024】MogaNet:多阶门控聚合网络
  • 小语言模型(SLM):构建可扩展智能体AI的关键
  • ​​[硬件电路-293]:不同频率对应不同周期时间对应表