Linux nm命令

原文地址:http://t.zoukankan.com/downey-blog-p-10477835.html

1. 什么是nm

nm命令是GNU Binutils二进制工具集的一员,用于显示目标文件中的符号。如果没有为nm命令指出目标文件,则nm假定目标文件是a.out。

该命令用来列出指定文件中的符号(如常用的函数名、变量等,以及这些符号存储的区域)。

帮助手册查看:man nm
使用手册查看:man -h

目标文件、库文件、可执行文件

首先,提到这三种文件,我们不得不提的就是gcc的编译流程:预编译,编译,汇编,链接。

  • 目标文件 :常说的目标文件是我们的程序文件(.c/.cpp,.h)经过预编译,编译,汇编过程生成的二进制文件,不经过链接过程,编译生成指令为:gcc -c hello.c
  • 库文件: 分为静态库和动态库,这里不做过多介绍,库文件是由多个二进制文件打包而成,生成的.a文件,示例:ar -rsc liba.a test1.o test2.o test3.o 将test1.o test2.o test3.o三个文件打包成liba.a库文件
  • 可执行文件:可执行文件是由多个二进制文件或者库文件(由上所得,库文件其实是二进制文件的集合)经过链接过程生成的一个可执行文件,对应windows下的.exe文件,可执行文件中有且仅有一个main()函数(用户程序入口,一般由bootloader指定,当然也可以改),一般情况下,二进制文件和库文件中是不包含main()函数的,但是在linux下用户有绝对的自由,做一个包含main函数的库文件也是可以使用的,但这不属于常规操作,不作讨论。

上述三种文件的格式都是二进制文件。

2. 为什么要用到nm

在上述提到的三种文件中,用编辑器是无法查看其内容的(乱码),所以当我们有这个需求(例如debug,查看内存分布的时候)去查看一个二进制文件里包含了哪些内容时,这时候就将用到一些特殊工具,linux下的nm命令就可以完全胜任(同时还有objdump和readelf工具,这里暂不作讨论)。

3. 怎么使用nm

如果你对linux下的各种概念还算了解的话,就该知道一般linux下的命令都会自带一些命令参数来满足各种应用需求,了解这些参数的使用是使用命令的开始。

man
那么,如何去了解一个命令呢,最好的方法就是linux下的man命令,linux是一个宝库,而man指令就相当于这个宝库的说明书。用法:man nm

这里面介绍了nm的各种参数以及详细用法,如果你有比较不错的英文水平和理解能力,可以直接参考man page中的内容。

nm的常用命令参数

-A 或-o或 --print-file-name:打印出每个符号属于的文件
-a或–debug-syms:打印出所有符号,包括debug符号
-B:BSD码显示
-C或–demangle[=style]:对低级符号名称进行解码,C++文件需要添加
–no-demangle:不对低级符号名称进行解码,默认参数
-D 或–dynamic:显示动态符号而不显示普通符号,一般用于动态库
-f format或–format=format:显示的形式,默认为bsd,可选为sysv和posix
-g或–extern-only:仅显示外部符号
-h或–help:国际惯例,显示命令的帮助信息
-n或-v或–numeric-sort:显示的符号以地址排序,而不是名称排序
-p或–no-sort:不对显示内容进行排序
-P或–portability:使用POSIX.2标准
-V或–version:国际管理,查看版本
–defined-only:仅显示定义的符号,这个从英文翻译过来可能会有偏差,故贴上原文:Display only defined symbols for each object file

好了,上述就是常用的命令参数,光说不练假把式,下面将给出一个示例来进一步理解nm用法:

示例代码:

#include <stdio.h>

#define MY_NUM 10

int g_mayue_num = 1;
int g_mayue_num_bk;
static int g_mayue_count = -1;
static int g_mayue_count_bk;

void mayue_print()
{
   printf("g_mayue_num:%d \n", g_mayue_num);
}

int main()
{
   int i_mayue_num = 1;	//nm 查看不到局部变量
   /* 我是一个 C 程序 */
   printf("Hello, World! %d \n", MY_NUM);
   
   mayue_print();
   return 0;
}

编译指令:gcc hello.c 会生出a.out可执行文件
在这里插入图片描述
下面我们再来解析输出信息中各部分所代表的意思吧

  • 首先,前面那一串数字,指的就是地址
  • 然后,我们发现,每一个条目前面还有一个字母,类似’U’,‘B’,'D等等,其实这些符号代表的就是当前条目所对应的内存所在部分
  • 最右边的就是对应的符号内容了

首要的需要讲解的就是第二点中字符所对应的含义:
同样在还是在linux命令行下man nm指令可以得到:
在这里插入图片描述
以上面代码为例我们定义了带mayue的变量和函数,均可以看到。

问题:

nm查看所有的函数

nm查看自定义的函数(不包含系统函数、比如printf)

nm查看定义的变量

4. 参考资料

  1. linux中的nm命令简介
  2. Linux nm 命令使用及符号含义
  3. nm命令中符号类型详解
  4. nm 命令 程序符号信息查看
  5. https://www.codetd.com/article/10980761

示例

nm -n myapp

对符号表中常见的变量、函数标识总结如下:(地址由底到高)

  • U 引用的外部函数
  • T 自定义函数(本文件内)
  • t 尚未分析
  • V
  • D 已初始化的全局变量(如int, char, float等)
  • d 已初始化的静态变量(包括全局静态变量、局部静态变量)
  • B 未初始化的全局变量,存放在bss段(结构体、枚举)
  • b 未初始化的static静态变量,存放在bss段(结构体、枚举)

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值