[Linux服务器] Linux nm命令详解

1558 0
Honkers 2025-3-8 13:32:56 | 显示全部楼层 |阅读模式

1、nm命令

nm命令是Linux下自带的强大的文本分析工具,是命令来源于name的简写。该命令用来列出指定文件中的符号(如常用的函数名、变量等,以及这些符号存储的区域)。它显示指定文件中的符号信息,文件可以是对象文件、可执行文件或对象文件库。如果文件中没有包含符号信息,nm报告该情况,单不把他解释为出错。nm缺省情况下报告十进制符号表示法下的数字值。

2、nm命令参数详解

nm命令可选参数如下:

  1. nm [-A|-o|--print-file-name] [-a|--debug-syms]
  2. [-B|--format=bsd] [-C|--demangle[=style]]
  3. [-D|--dynamic] [-fformat|--format=format]
  4. [-g|--extern-only] [-h|--help]
  5. [-l|--line-numbers] [--inlines]
  6. [-n|-v|--numeric-sort]
  7. [-P|--portability] [-p|--no-sort]
  8. [-r|--reverse-sort] [-S|--print-size]
  9. [-s|--print-armap] [-t radix|--radix=radix]
  10. [-u|--undefined-only] [-V|--version]
  11. [-X 32_64] [--defined-only] [--no-demangle]
  12. [--plugin name]
  13. [--no-recurse-limit|--recurse-limit]]
  14. [--size-sort] [--special-syms]
  15. [--synthetic] [--with-symbol-versions] [--target=bfdname]
  16. [objfile...]
复制代码

参数说明:

  • -A/-o/–print-file-name: 在输出时加上文件名;
  • -a/–debug-syms: 输出所有符号,包含debugger-only symbols;
  • -B/–format=bsd: BSD码显示,兼容MIPS nm;
  • -C/–demangle: 将低级符号名解析为用户级名字,可以使得C++函数名更具可读性;
  • -D/–dynamic: 显示动态符号。该选项只对动态目标(如特定类型的共享库)有意义;
  • -f format/–format=format 使用format格式输出。format可以选取bsd、sysv或posix,该选项在GNU的nm中有用。默认为bsd
  • -g/–extern-only: 只显示外部符号;
  • -l/–line-numbers: 对于每个符号,使用debug信息找到文件名和行号;
  • -n/-v/–numeric-sort: 按符号对应地址的顺序排序,而非按符号名字字符顺序排序;
  • -P/–portability: 按照POSIX2.0标准格式输出,等同于使用 -f posix;
  • -p/–no-sort: 按照目标文件中遇到的符号顺序显示,不排序;
  • -r/–reverse-sort: 反转排序;
  • -s/–print-armap: 当列出库成员符号时,包含索引。索引的内容:模块和其包含名字的映射;
  • -u/–undefined-only: 只显示未定义符号;
  • –defined-only: 只显示定义了的符号。

3、nm命令使用方法

下面使用的用例时一段简单的c语言代码,其源码如下:

  1. imaginemiracle@ubuntu:typeof$ cat typeof.c
  2. #include <stdio.h>
  3. int func(void)
  4. {
  5. return 6;
  6. }
  7. int func1(int id)
  8. {
  9. return id;
  10. }
  11. int main(int argc, char* argv[])
  12. {
  13. typeof(func()) id = func();
  14. typeof(func1(12)) id1 = func1(12);
  15. int a = 1;
  16. typeof(a) b = 2; // 获取变量 i 的类型并以此类型定义变量 b
  17. int *a1 = &a;
  18. typeof(a1) b1 = &b; // 获取变量 a1 的类型并以此类型定义变量 b1
  19. printf("id: %d\n", id);
  20. printf("id1: %d\n", id1);
  21. printf("a: %d\n", a);
  22. printf("b: %d\n", b);
  23. printf("a1: %d\n", *a1);
  24. printf("b1: %d\n", *b1);
  25. typeof(1 == a) bool_01 = (1 == a);
  26. typeof(2 == a) bool_02 = (2 == a);
  27. if (bool_01) {
  28. printf("It's true!\n");
  29. } else {
  30. printf("It's false!\n");
  31. }
  32. if (bool_02) {
  33. printf("It's true!\n");
  34. } else {
  35. printf("It's false!\n");
  36. }
  37. return 0;
  38. }
复制代码

这里我们直接使用nm命令将a.out(上文代码编译出的elf文件)里的符号全部列出。

  1. imaginemiracle@ubuntu:typeof$ nm a.out
  2. 0000000000004010 B __bss_start
  3. 0000000000004010 b completed.8061
  4. w __cxa_finalize@@GLIBC_2.2.5
  5. 0000000000004000 D __data_start
  6. 0000000000004000 W data_start
  7. 00000000000010d0 t deregister_tm_clones
  8. 0000000000001140 t __do_global_dtors_aux
  9. 0000000000003db0 d __do_global_dtors_aux_fini_array_entry
  10. 0000000000004008 D __dso_handle
  11. 0000000000003db8 d _DYNAMIC
  12. 0000000000004010 D _edata
  13. 0000000000004018 B _end
  14. 0000000000001378 T _fini
  15. 0000000000001180 t frame_dummy
  16. 0000000000003da8 d __frame_dummy_init_array_entry
  17. 00000000000021e4 r __FRAME_END__
  18. 0000000000001189 T func
  19. 0000000000001198 T func1
  20. 0000000000003fa8 d _GLOBAL_OFFSET_TABLE_
  21. w __gmon_start__
  22. 000000000000204c r __GNU_EH_FRAME_HDR
  23. 0000000000001000 t _init
  24. 0000000000003db0 d __init_array_end
  25. 0000000000003da8 d __init_array_start
  26. 0000000000002000 R _IO_stdin_used
  27. w _ITM_deregisterTMCloneTable
  28. w _ITM_registerTMCloneTable
  29. 0000000000001370 T __libc_csu_fini
  30. 0000000000001300 T __libc_csu_init
  31. U __libc_start_main@@GLIBC_2.2.5
  32. 00000000000011a8 T main
  33. U printf@@GLIBC_2.2.5
  34. U puts@@GLIBC_2.2.5
  35. 0000000000001100 t register_tm_clones
  36. U __stack_chk_fail@@GLIBC_2.4
  37. 00000000000010a0 T _start
  38. 0000000000004010 D __TMC_END__
复制代码

如上面nm列出的结果中每个符号意义如下:
对于每个符号,nm 显示:

• 符号值,由选项选择的基数(见下文),或默认为十六进制。

• 符号类型。至少使用以下类型;其他的也取决于对象文件格式。如果是小写,符号通常是本地的;如果是大写,则符号是全局的(外部的)。然而,对于特殊的全局符号(“u”、“v”和“w”)显示了一些小写符号

符号描述
A符号的值是绝对值,不会通过进一步的链接而改变。
B/b符号在 BSS 数据段中。本节通常包含零初始化或未初始化的数据,尽管确切的行为取决于系统。
C这个符号很常见。常用符号是未初始化的数据。链接时,多个常用符号可能以相同的名称出现。如果符号在任何地方定义,则常用符号被视为未定义的引用。
D/d符号在初始化数据段中。
G/g符号在小对象的初始化数据段中。一些目标文件格式允许更有效地访问小型数据对象,例如全局int变量,而不是大型全局数组。
i对于PE格式文件,这表示符号位于特定于实现的部分中 DLL。对于ELF格式文件,这表明该符号是一个间接函数。这是一个GNU对标准ELF 符号类型集的扩展。它表示一个符号,如果被一个重定位不计算其地址,而是必须在运行时调用。运行时然后执行将返回要在重定位中使用的值。
I该符号是对另一个符号的间接引用。
N该符号是调试符号。
n符号在只读数据段中。
p符号在堆栈展开部分中。
R/r该符号位于只读数据段中。
S/s该符号在小对象的未初始化或零初始化数据段中。
T/t符号在文本(代码)部分。
U符号未定义。
u该符号是唯一的全局符号。这是标准ELF符号集的GNU扩展绑定。对于这样的符号,动态链接器将确保在整个过程中只有一个具有此名称和类型的符号正在使用中。
V/v符号是弱对象。当弱定义符号与正常定义符号链接时,使用正常定义的符号没有错误。当一个弱的未定义符号被链接并且该符号没有定义,弱符号的值变为零,没有错误。在某些系统上,大写表示已指定默认值。
W/w该符号是一个弱符号,没有被专门标记为弱对象符号。当一个弱定义符号与正常定义符号链接,正常定义符号与没有错误。当一个弱的未定义符号被链接并且该符号未定义时,符号以系统特定的方式确定,没有错误。在某些系统上,大写表示已指定默认值。
-该符号是a.out目标文件中的stabs符号。在这种情况下,打印的下一个值是stabs other字段、stabs desc字段和stab类型。刺符号用于保持调试信息。
符号类型未知,或目标文件格式为sp

觉得这篇文章对你有帮助的话,就留下一个赞吧^v^*
请尊重作者,转载还请注明出处!感谢配合~
[作者]: Imagine Miracle
[版权]: 本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
[本文链接]: https://blog.csdn.net/qq_36393978/article/details/124104635

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

中国红客联盟公众号

联系站长QQ:5520533

admin@chnhonker.com
Copyright © 2001-2026 Discuz Team. Powered by Discuz! X3.5 ( 粤ICP备13060014号 )|天天打卡 本站已运行