转:http://blog.csdn.net/stpeace/article/details/47089585

一般来说, 搞linux开发的人, 才会用到nm命令, 非开发的人, 应该用不到。 虽然nm很简单, 但是还是有必要写几句, 聊表心意。

nm不是ni ma的缩写, 当然, 也不是ni mei的缩写, 而是names的缩写, nm命令主要是用来列出某些文件中的符号(说白了就是一些函数和全局变量等)。  下面, 我们一起来看看。

test.h为:

  1. void print();
void print();

test.c为:

  1. #include <stdio.h>
  2. #include "test.h"
  3. void print()
  4. {
  5. printf("rainy days\n");
  6. }
#include <stdio.h>
#include "test.h" void print()
{
printf("rainy days\n");
}

main.c为:

  1. #include "test.h"
  2. int main()
  3. {
  4. print();
  5. return 0;
  6. }
#include "test.h"

int main()
{
print();
return 0;
}

好, 我们看看nm命令的作用效果, 如下:

  1. [taoge@localhost learn_nm]$ nm *
  2. nm: main.c: File format not recognized
  3. nm: test.c: File format not recognized
  4. nm: test.h: File format not recognized
  5. [taoge@localhost learn_nm]$
[taoge@localhost learn_nm]$ nm *
nm: main.c: File format not recognized
nm: test.c: File format not recognized
nm: test.h: File format not recognized
[taoge@localhost learn_nm]$

ni ma, 啥都没有, 这说明nm对这类文件无用。

继续看nm能否读取目标文件和可执行文件:

  1. [taoge@localhost learn_nm]$ ls
  2. main.c  test.c  test.h
  3. [taoge@localhost learn_nm]$ gcc -c test.c main.c
  4. [taoge@localhost learn_nm]$ gcc test.o main.o
  5. [taoge@localhost learn_nm]$ ./a.out
  6. rainy days
  7. [taoge@localhost learn_nm]$ nm *
  8. a.out:
  9. 08049564 d _DYNAMIC
  10. 08049630 d _GLOBAL_OFFSET_TABLE_
  11. 0804849c R _IO_stdin_used
  12. w _Jv_RegisterClasses
  13. 08049554 d __CTOR_END__
  14. 08049550 d __CTOR_LIST__
  15. 0804955c D __DTOR_END__
  16. 08049558 d __DTOR_LIST__
  17. 0804854c r __FRAME_END__
  18. 08049560 d __JCR_END__
  19. 08049560 d __JCR_LIST__
  20. 0804964c A __bss_start
  21. 08049648 D __data_start
  22. 08048450 t __do_global_ctors_aux
  23. 08048330 t __do_global_dtors_aux
  24. 080484a0 R __dso_handle
  25. w __gmon_start__
  26. 0804844a T __i686.get_pc_thunk.bx
  27. 08049550 d __init_array_end
  28. 08049550 d __init_array_start
  29. 080483e0 T __libc_csu_fini
  30. 080483f0 T __libc_csu_init
  31. U __libc_start_main@@GLIBC_2.0
  32. 0804964c A _edata
  33. 08049654 A _end
  34. 0804847c T _fini
  35. 08048498 R _fp_hw
  36. 08048290 T _init
  37. 08048300 T _start
  38. 0804964c b completed.5963
  39. 08049648 W data_start
  40. 08049650 b dtor_idx.5965
  41. 08048390 t frame_dummy
  42. 080483c8 T main
  43. 080483b4 T print
  44. U puts@@GLIBC_2.0
  45. nm: main.c: File format not recognized
  46. main.o:
  47. 00000000 T main
  48. U print
  49. nm: test.c: File format not recognized
  50. nm: test.h: File format not recognized
  51. test.o:
  52. 00000000 T print
  53. U puts
  54. [taoge@localhost learn_nm]$
[taoge@localhost learn_nm]$ ls
main.c test.c test.h
[taoge@localhost learn_nm]$ gcc -c test.c main.c
[taoge@localhost learn_nm]$ gcc test.o main.o
[taoge@localhost learn_nm]$ ./a.out
rainy days
[taoge@localhost learn_nm]$ nm * a.out:
08049564 d _DYNAMIC
08049630 d _GLOBAL_OFFSET_TABLE_
0804849c R _IO_stdin_used
w _Jv_RegisterClasses
08049554 d __CTOR_END__
08049550 d __CTOR_LIST__
0804955c D __DTOR_END__
08049558 d __DTOR_LIST__
0804854c r __FRAME_END__
08049560 d __JCR_END__
08049560 d __JCR_LIST__
0804964c A __bss_start
08049648 D __data_start
08048450 t __do_global_ctors_aux
08048330 t __do_global_dtors_aux
080484a0 R __dso_handle
w __gmon_start__
0804844a T __i686.get_pc_thunk.bx
08049550 d __init_array_end
08049550 d __init_array_start
080483e0 T __libc_csu_fini
080483f0 T __libc_csu_init
U __libc_start_main@@GLIBC_2.0
0804964c A _edata
08049654 A _end
0804847c T _fini
08048498 R _fp_hw
08048290 T _init
08048300 T _start
0804964c b completed.5963
08049648 W data_start
08049650 b dtor_idx.5965
08048390 t frame_dummy
080483c8 T main
080483b4 T print
U puts@@GLIBC_2.0
nm: main.c: File format not recognized main.o:
00000000 T main
U print
nm: test.c: File format not recognized
nm: test.h: File format not recognized test.o:
00000000 T print
U puts
[taoge@localhost learn_nm]$

可以看到, 对于目标文件和可执行文件而言, 均可以获得其中的函数, 如print函数。

我们继续看静态库和动态库, 如下:

  1. [taoge@localhost learn_nm]$ ls
  2. main.c  test.c  test.h
  3. [taoge@localhost learn_nm]$ gcc -c test.c
  4. [taoge@localhost learn_nm]$ ar rcs libtest.a test.o
  5. [taoge@localhost learn_nm]$ gcc -shared -fPIC -o libtest.so test.o
  6. [taoge@localhost learn_nm]$ ls
  7. libtest.a  libtest.so  main.c  test.c  test.h  test.o
  8. [taoge@localhost learn_nm]$ nm lib*
  9. libtest.a:
  10. test.o:
  11. 00000000 T print
  12. U puts
  13. libtest.so:
  14. 000014bc a _DYNAMIC
  15. 00001590 a _GLOBAL_OFFSET_TABLE_
  16. w _Jv_RegisterClasses
  17. 000014a8 d __CTOR_END__
  18. 000014a4 d __CTOR_LIST__
  19. 000014b0 d __DTOR_END__
  20. 000014ac d __DTOR_LIST__
  21. 000004a0 r __FRAME_END__
  22. 000014b4 d __JCR_END__
  23. 000014b4 d __JCR_LIST__
  24. 000015a4 A __bss_start
  25. w __cxa_finalize@@GLIBC_2.1.3
  26. 00000440 t __do_global_ctors_aux
  27. 00000350 t __do_global_dtors_aux
  28. 000014b8 d __dso_handle
  29. w __gmon_start__
  30. 00000419 t __i686.get_pc_thunk.bx
  31. 000015a4 A _edata
  32. 000015ac A _end
  33. 00000478 T _fini
  34. 000002ec T _init
  35. 000015a4 b completed.5963
  36. 000015a8 b dtor_idx.5965
  37. 000003e0 t frame_dummy
  38. 00000420 T print
  39. U puts@@GLIBC_2.0
  40. [taoge@localhost learn_nm]$
[taoge@localhost learn_nm]$ ls
main.c test.c test.h
[taoge@localhost learn_nm]$ gcc -c test.c
[taoge@localhost learn_nm]$ ar rcs libtest.a test.o
[taoge@localhost learn_nm]$ gcc -shared -fPIC -o libtest.so test.o
[taoge@localhost learn_nm]$ ls
libtest.a libtest.so main.c test.c test.h test.o
[taoge@localhost learn_nm]$ nm lib* libtest.a: test.o:
00000000 T print
U puts libtest.so:
000014bc a _DYNAMIC
00001590 a _GLOBAL_OFFSET_TABLE_
w _Jv_RegisterClasses
000014a8 d __CTOR_END__
000014a4 d __CTOR_LIST__
000014b0 d __DTOR_END__
000014ac d __DTOR_LIST__
000004a0 r __FRAME_END__
000014b4 d __JCR_END__
000014b4 d __JCR_LIST__
000015a4 A __bss_start
w __cxa_finalize@@GLIBC_2.1.3
00000440 t __do_global_ctors_aux
00000350 t __do_global_dtors_aux
000014b8 d __dso_handle
w __gmon_start__
00000419 t __i686.get_pc_thunk.bx
000015a4 A _edata
000015ac A _end
00000478 T _fini
000002ec T _init
000015a4 b completed.5963
000015a8 b dtor_idx.5965
000003e0 t frame_dummy
00000420 T print
U puts@@GLIBC_2.0
[taoge@localhost learn_nm]$

可以看到, 我们可以从静态库和动态库中获取到函数名称, 如print函数。

好, 我们再来看看全局变量的情形, 我们把main.c改为:

  1. #include <stdio.h>
  2. int add(int x, int y)
  3. {
  4. return x + y;
  5. }
  6. int aaa;
  7. int bbb = 1;
  8. char szTest[] = "good";
  9. int main()
  10. {
  11. int ccc = 2;
  12. return 0;
  13. }
#include <stdio.h>

int add(int x, int y)
{
return x + y;
} int aaa;
int bbb = 1;
char szTest[] = "good"; int main()
{
int ccc = 2;
return 0;
}

然后用nm分析a.out(注意, 如果只有nm命令, 则默认a.out为其要处理的文件):

  1. [taoge@localhost learn_nm]$ ls
  2. main.c
  3. [taoge@localhost learn_nm]$ gcc main.c
  4. [taoge@localhost learn_nm]$ ./a.out
  5. [taoge@localhost learn_nm]$ nm a.out
  6. 08049538 d _DYNAMIC
  7. 08049604 d _GLOBAL_OFFSET_TABLE_
  8. 0804847c R _IO_stdin_used
  9. w _Jv_RegisterClasses
  10. 08049528 d __CTOR_END__
  11. 08049524 d __CTOR_LIST__
  12. 08049530 D __DTOR_END__
  13. 0804952c d __DTOR_LIST__
  14. 08048520 r __FRAME_END__
  15. 08049534 d __JCR_END__
  16. 08049534 d __JCR_LIST__
  17. 08049628 A __bss_start
  18. 08049618 D __data_start
  19. 08048430 t __do_global_ctors_aux
  20. 08048310 t __do_global_dtors_aux
  21. 08048480 R __dso_handle
  22. w __gmon_start__
  23. 0804842a T __i686.get_pc_thunk.bx
  24. 08049524 d __init_array_end
  25. 08049524 d __init_array_start
  26. 080483c0 T __libc_csu_fini
  27. 080483d0 T __libc_csu_init
  28. U __libc_start_main@@GLIBC_2.0
  29. 08049628 A _edata
  30. 08049634 A _end
  31. 0804845c T _fini
  32. 08048478 R _fp_hw
  33. 08048274 T _init
  34. 080482e0 T _start
  35. 08049630 B aaa
  36. 08048394 T add
  37. 0804961c D bbb
  38. 08049628 b completed.5963
  39. 08049618 W data_start
  40. 0804962c b dtor_idx.5965
  41. 08048370 t frame_dummy
  42. 080483a2 T main
  43. 08049620 D szTest
  44. [taoge@localhost learn_nm]$
[taoge@localhost learn_nm]$ ls
main.c
[taoge@localhost learn_nm]$ gcc main.c
[taoge@localhost learn_nm]$ ./a.out
[taoge@localhost learn_nm]$ nm a.out
08049538 d _DYNAMIC
08049604 d _GLOBAL_OFFSET_TABLE_
0804847c R _IO_stdin_used
w _Jv_RegisterClasses
08049528 d __CTOR_END__
08049524 d __CTOR_LIST__
08049530 D __DTOR_END__
0804952c d __DTOR_LIST__
08048520 r __FRAME_END__
08049534 d __JCR_END__
08049534 d __JCR_LIST__
08049628 A __bss_start
08049618 D __data_start
08048430 t __do_global_ctors_aux
08048310 t __do_global_dtors_aux
08048480 R __dso_handle
w __gmon_start__
0804842a T __i686.get_pc_thunk.bx
08049524 d __init_array_end
08049524 d __init_array_start
080483c0 T __libc_csu_fini
080483d0 T __libc_csu_init
U __libc_start_main@@GLIBC_2.0
08049628 A _edata
08049634 A _end
0804845c T _fini
08048478 R _fp_hw
08048274 T _init
080482e0 T _start
08049630 B aaa
08048394 T add
0804961c D bbb
08049628 b completed.5963
08049618 W data_start
0804962c b dtor_idx.5965
08048370 t frame_dummy
080483a2 T main
08049620 D szTest
[taoge@localhost learn_nm]$

可以看到, 不仅有add函数, 还有全局变量aaa, bbb和szTest, 要注意, aaa是未初始化的, 所以在Bss段, 而bbb、szTest是初始化了的, 所以在Data段。 值得注意的是, 并没有ccc, 因为ccc是局部变量, nm看不到的。

我们还应该注意到, 在上面看不到"good", 为啥呢? 因为nm是用来看szTest而非"good"的。 别忘了, 我们之前介绍过的strings命令可干这事, 如下:

  1. [taoge@localhost learn_nm]$ ls
  2. a.out  main.c
  3. [taoge@localhost learn_nm]$ strings a.out
  4. /lib/ld-linux.so.2
  5. __gmon_start__
  6. libc.so.6
  7. _IO_stdin_used
  8. __libc_start_main
  9. GLIBC_2.0
  10. PTRh
  11. [^_]
  12. good
  13. [taoge@localhost learn_nm]$
[taoge@localhost learn_nm]$ ls
a.out main.c
[taoge@localhost learn_nm]$ strings a.out
/lib/ld-linux.so.2
__gmon_start__
libc.so.6
_IO_stdin_used
__libc_start_main
GLIBC_2.0
PTRh
[^_]
good
[taoge@localhost learn_nm]$

nm命令主要列出特性文件中的符号信息, 具体更加详细的用法, 请问man, 我就不再过多介绍了。

linux中的nm命令简介的更多相关文章

  1. linux中的strings命令简介2

    摘自:http://blog.csdn.net/stpeace/article/details/46641069 linux中的strings命令简介 之前我们聊过linux strings的用法和用 ...

  2. linux中的strings命令简介

    摘自:http://blog.csdn.net/stpeace/article/details/46641069 linux中的strings命令简介 在linux下搞软件开发的朋友, 几乎没有不知道 ...

  3. linux中的ldd命令简介

    转载自:http://blog.csdn.net/stpeace/article/details/47069215 在linux中, 有些命令是大家通用的, 比如ls, rm, mv, cp等等, 这 ...

  4. linux中的strip命令简介------给文件脱衣服

    1.去掉-g,等于程序做了--strip-debug2.strip程序,等于程序做了--strip-debug和--strip-symbol 作为一名Linux开发人员, 如果没有听说过strip命令 ...

  5. linux中的strip命令简介------给文件脱衣服【转】

    转自:http://blog.csdn.net/stpeace/article/details/47090255 版权声明:本文为博主原创文章,转载时请务必注明本文地址, 禁止用于任何商业用途, 否则 ...

  6. linux中的strip命令简介

    转载:https://blog.csdn.net/qq_37858386/article/details/78559490 strip:去除,剥去     一.下面是man strip获得到的信息,简 ...

  7. Python学习之旅:使用Python实现Linux中的ls命令

    一.写在前面 前几天在微信上看到这样一篇文章,链接为:https://mp.weixin.qq.com/s/rl6Sgv3uk_IpoFAx6cWa8w,在这篇文章中,有这样一段话,吸引了我的注意: ...

  8. Linux中的历史命令

    Linux中的历史命令一般保存在用户    /root/.bash_history history 选项 历史命令保存文件夹 选项     -c:清空历史命令     -w :把缓存中的历史命令写入历 ...

  9. 关于XShell的常见使用和设置以及Linux中的常见命令.

    本文部分转自:http://sundful.iteye.com/blog/704079 和 http://www.vckai.com/p/5 有时候在XShell中操作的一些命令傻傻的分不清这个命令到 ...

随机推荐

  1. Python_01 在DOS环境运行python程序

    >怎么在DOS环境运行一个python程序 >>在文本编辑器中编辑程序,最后保存成   文件名.py  的格式 >>在DOS界面下找到源程序所在的路径,然后用  pyth ...

  2. linux:问题

    1>.Xshell远程连接linux闲置时间过长会自动中断连接: 2>.在linux环境下乱码: 3>.在linux下面执行mv /bin/ls /root/bin之后执行ls就不能 ...

  3. Iterator和ListIterator主要区别(转)

    Iterator和ListIterator主要区别有: 一.ListIterator有add()方法,可以向List中添加对象,而Iterator不能. 二.ListIterator和Iterator ...

  4. SQL 数据库 right join 和left join 的区别

    left join(左联接) 返回包括左表中的所有记录和右表中联结字段相等的记录 right join(右联接) 返回包括右表中的所有记录和左表中联结字段相等的记录inner join(等值连接) 只 ...

  5. HttpContext.Current 的缺陷

    了解ASP.NET的开发人员都知道它有个非常强大的对象 HttpContext,而且为了方便,ASP.NET还为它提供了一个静态属性HttpContext.Current来访问它,今天的博客打算就从H ...

  6. extjs 4.2 日期控件 选择时分秒功能

    因为不支持时分秒,然后在网上也找了一段时间的插件,但是感觉起来都不大方便,最后找一个插件,只需要引用js文件,然后修改类型,就可以实现extjs下面的datafield带时分秒功能了. 步骤: 只需要 ...

  7. 判断java中两个对象是否相等

    java中的基本数据类型判断是否相等,直接使用"=="就行了,相等返回true,否则,返回false. 但是java中的引用类型的对象比较变态,假设有两个引用对象obj1,obj2 ...

  8. 反射认识_06_ArrayList_HashSet区别

    包01: package ReflectionCollection; public class ReflectionConstructorPoint { private int x; public i ...

  9. paper 86:行人检测资源(上)综述文献【转载,以后使用】

    行人检测具有极其广泛的应用:智能辅助驾驶,智能监控,行人分析以及智能机器人等领域.从2005年以来行人检测进入了一个快速的发展阶段,但是也存在很多问题还有待解决,主要还是在性能和速度方面还不能达到一个 ...

  10. C# 控制台程序如何防止启动多个实例

    ==================================================================================================== ...