10 个实用的 Linux nm 命令示例
nm 命令提供有关在目标文件或可执行文件中使用的符号的信息。
“nm”命令提供的默认信息是:
- 符号的虚拟地址
- 描述符号类型的字符。如果字符是小写,则符号是本地的,但如果字符是大写的,则符号是外部的
- 符号名称
标识符号类型的字符描述:
- A : 全局绝对符号。
- a :本地绝对符号。
- B : 全局 bss 符号。
- b : 本地 bss 符号。
- D : 全局数据符号。
- d:本地数据符号。
- f : 源文件名符号。
- L:全局线程局部符号 (TLS)。
- l:静态线程局部符号(TLS)。
- T:全局文本符号。
- t :本地文本符号。
- U:未定义的符号。
请注意,此列表并不详尽,但包含一些重要的符号类型。有关完整信息,请参阅此实用程序的手册页。
使用“nm”实用程序的默认方式是:
$ nm <object file or executable name>
如果没有给出可执行名称,则 nm 假定名称为“a.out”。
有了关于这个实用程序的基本概念,人们可能会质疑为什么需要这些信息?
好吧,假设您有一个由许多不同的目标文件组成的可执行文件。现在假设在编译代码时,链接器给出了关于未解析符号“temp”的错误。现在,如果代码太大并且包含很多标题,那么在代码中查找符号“temp”将成为一场噩梦。正是在这里,这个实用程序来拯救。通过一些额外的选项,此实用程序还提供了符号所在的文件。
从现在开始,我们对 nm 实用程序有了一个基本的了解。让我们通过一些实用的命令来了解这个实用程序的用法。
1. 显示引用符号的目标文件
以下命令显示当前目录中引用符号 'func' 的所有目标文件
$ nm -A ./*.o | grep func
./hello2.o:0000000000000000 T func_1
./hello3.o:0000000000000000 T func_2
./hello4.o:0000000000000000 T func_3
./main.o: U func
./reloc.o: U func
./reloc.o:0000000000000000 T func1
./test1.o:0000000000000000 T func
./test.o: U func
请注意,-A 标志用于显示文件名以及其他信息。所以我们看到在输出中我们得到了所有使用了符号“func”的目标文件。在我们想知道哪些目标文件如何使用特定符号的情况下,这可能非常有用。
2. 显示可执行文件中的所有未定义符号
以下命令列出了可执行文件 '1' 中的所有未定义符号
$ nm -u 1
w _Jv_RegisterClasses
w __gmon_start__
U __libc_start_main@@GLIBC_2.2.5
U free@@GLIBC_2.2.5
U malloc@@GLIBC_2.2.5
U printf@@GLIBC_2.2.5
请注意,在这种情况下使用标志“-u”仅列出未定义的符号。这在人们可能想知道代码中使用的未定义符号可能真正无法解析或可以通过共享库在运行时解析的情况下非常有用。
3. 显示可执行文件中的所有符号
以下命令列出了可执行文件“namepid”中的所有符号,但按它们的地址排序
$ nm -n namepid
w _Jv_RegisterClasses
w __gmon_start__
U __libc_start_main@@GLIBC_2.2.5
U exit@@GLIBC_2.2.5
U fclose@@GLIBC_2.2.5
U fgets@@GLIBC_2.2.5
U fopen@@GLIBC_2.2.5
U fork@@GLIBC_2.2.5
U memset@@GLIBC_2.2.5
U printf@@GLIBC_2.2.5
U puts@@GLIBC_2.2.5
U signal@@GLIBC_2.2.5
U sleep@@GLIBC_2.2.5
U strchr@@GLIBC_2.2.5
U strlen@@GLIBC_2.2.5
U strncat@@GLIBC_2.2.5
U strncpy@@GLIBC_2.2.5
U system@@GLIBC_2.2.5
0000000000400778 T _init
00000000004008a0 T _start
00000000004008cc t call_gmon_start
00000000004008f0 t __do_global_dtors_aux
...
...
...
我们看到,通过使用标志“-n”,输出首先按照未定义符号排序,然后根据地址排序。排序可以使调试问题的开发人员的生活变得轻松。
4. 搜索符号并显示其大小
以下命令搜索符号“abc”并显示其大小
$ nm -S 1 | grep abc
0000000000601040 0000000000000004 B abc
所以我们看到标志 -S 显示了关于符号“abc”大小的额外信息
5. 在可执行文件中显示动态符号
以下命令显示在可执行文件“1”中的动态符号上。
$ nm -D 1
w __gmon_start__
U __libc_start_main
U free
U malloc
U printf
如果有人有兴趣了解只能在运行时由共享库解析的符号,这可能非常有用。
6.提取各种类型的符号
nm 命令的另一个强大功能是能够从各种类型的目标文件格式中提取符号。通常在 Linux 上,我们有 'a.out' 或 ELF 格式的对象或可执行代码,但如果对象或可执行代码是其他格式,那么 nm 也会为其提供一个标志 '-target'。
7.更改nm输出的格式
默认情况下,nm 显示的输出格式是 bsd 类型。我们可以使用标志 -f 更改格式。以下命令以 posix 样式显示 nm 命令的输出。
$ nm -u -f posix 1
_Jv_RegisterClasses w
__gmon_start__ w
__libc_start_main@@GLIBC_2.2.5 U
free@@GLIBC_2.2.5 U
malloc@@GLIBC_2.2.5 U
printf@@GLIBC_2.2.5 U
同样,如果我们希望输出采用 systemV 样式,我们可以使用“-f sysv”。
8. 只显示可执行文件的外部符号
以下命令仅列出可执行文件中的外部符号
$ nm -g 1
0000000000400728 R _IO_stdin_used
w _Jv_RegisterClasses
0000000000600e30 D __DTOR_END__
0000000000601030 A __bss_start
0000000000601020 D __data_start
0000000000601028 D __dso_handle
w __gmon_start__
0000000000400640 T __libc_csu_fini
0000000000400650 T __libc_csu_init
...
请注意,使用标志 -g 只能输出外部符号。这在专门调试外部符号时会派上用场。
9. 按符号大小对 nm 输出进行排序
以下命令按符号大小对输出进行排序
$ nm -g --size-sort 1
0000000000000002 T __libc_csu_fini
0000000000000004 R _IO_stdin_used
0000000000000004 B abc
0000000000000084 T main
0000000000000089 T __libc_csu_init
请注意,标志 –size-sort 根据大小对输出进行排序。如前所述,-g 用于仅显示外部符号。
10. 在文件中指定 nm 选项
nm 的另一个有价值的特性是它可以从文件中获取命令行输入。您可以指定文件中的所有选项,并将文件名指定给 nm 命令,其余的工作将为您完成。例如,在以下命令中,nm 实用程序从文件“nm_file”读取命令行输入并生成输出
请注意,如果您提供文件名,则需要符号“@”。
$ nm @nm_file
0000000000000002 T __libc_csu_fini
0000000000000004 R _IO_stdin_used
0000000000000004 B abc
0000000000000084 T main
0000000000000089 T __libc_csu_init
- 点赞
- 收藏
- 关注作者
评论(0)