Chinaunix首页 | 论坛 | 博客
  • 博客访问: 3759352
  • 博文数量: 880
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 6155
  • 用 户 组: 普通用户
  • 注册时间: 2016-11-11 09:12
个人简介

To be a better coder

文章分类

全部博文(880)

文章存档

2022年(5)

2021年(60)

2020年(175)

2019年(207)

2018年(210)

2017年(142)

2016年(81)

分类: LINUX

2017-11-21 14:57:17

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

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

  

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

       test.h为:


  1. void print();  


      test.c为:


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


       main.c为:


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

      好, 我们看看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]$   

      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.   
  9. a.out:  
  10. 08049564 d _DYNAMIC  
  11. 08049630 d _GLOBAL_OFFSET_TABLE_  
  12. 0804849c R _IO_stdin_used  
  13.          w _Jv_RegisterClasses  
  14. 08049554 d __CTOR_END__  
  15. 08049550 d __CTOR_LIST__  
  16. 0804955c D __DTOR_END__  
  17. 08049558 d __DTOR_LIST__  
  18. 0804854c r __FRAME_END__  
  19. 08049560 d __JCR_END__  
  20. 08049560 d __JCR_LIST__  
  21. 0804964c A __bss_start  
  22. 08049648 D __data_start  
  23. 08048450 t __do_global_ctors_aux  
  24. 08048330 t __do_global_dtors_aux  
  25. 080484a0 R __dso_handle  
  26.          w __gmon_start__  
  27. 0804844a T __i686.get_pc_thunk.bx  
  28. 08049550 d __init_array_end  
  29. 08049550 d __init_array_start  
  30. 080483e0 T __libc_csu_fini  
  31. 080483f0 T __libc_csu_init  
  32.          U __libc_start_main@@GLIBC_2.0  
  33. 0804964c A _edata  
  34. 08049654 A _end  
  35. 0804847c T _fini  
  36. 08048498 R _fp_hw  
  37. 08048290 T _init  
  38. 08048300 T _start  
  39. 0804964c b completed.5963  
  40. 08049648 W data_start  
  41. 08049650 b dtor_idx.5965  
  42. 08048390 t frame_dummy  
  43. 080483c8 T main  
  44. 080483b4 T print  
  45.          U puts@@GLIBC_2.0  
  46. nm: main.c: File format not recognized  
  47.   
  48. main.o:  
  49. 00000000 T main  
  50.          U print  
  51. nm: test.c: File format not recognized  
  52. nm: test.h: File format not recognized  
  53.   
  54. test.o:  
  55. 00000000 T print  
  56.          U puts  
  57. [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.   
  10. libtest.a:  
  11.   
  12. test.o:  
  13. 00000000 T print  
  14.          U puts  
  15.   
  16. libtest.so:  
  17. 000014bc a _DYNAMIC  
  18. 00001590 a _GLOBAL_OFFSET_TABLE_  
  19.          w _Jv_RegisterClasses  
  20. 000014a8 d __CTOR_END__  
  21. 000014a4 d __CTOR_LIST__  
  22. 000014b0 d __DTOR_END__  
  23. 000014ac d __DTOR_LIST__  
  24. 000004a0 r __FRAME_END__  
  25. 000014b4 d __JCR_END__  
  26. 000014b4 d __JCR_LIST__  
  27. 000015a4 A __bss_start  
  28.          w __cxa_finalize@@GLIBC_2.1.3  
  29. 00000440 t __do_global_ctors_aux  
  30. 00000350 t __do_global_dtors_aux  
  31. 000014b8 d __dso_handle  
  32.          w __gmon_start__  
  33. 00000419 t __i686.get_pc_thunk.bx  
  34. 000015a4 A _edata  
  35. 000015ac A _end  
  36. 00000478 T _fini  
  37. 000002ec T _init  
  38. 000015a4 b completed.5963  
  39. 000015a8 b dtor_idx.5965  
  40. 000003e0 t frame_dummy  
  41. 00000420 T print  
  42.          U puts@@GLIBC_2.0  
  43. [taoge@localhost learn_nm]$   

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



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


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

       然后用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]$   

        可以看到, 不仅有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]$   



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

阅读(1527) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~