zoukankan      html  css  js  c++  java
  • linux中的nm命令简介

    转: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.   
    4. void print()  
    5. {  
    6.     printf("rainy days ");  
    7. }  
    #include <stdio.h>
    #include "test.h"
    
    void print()
    {
    	printf("rainy days
    ");
    }

           main.c为:

    1. #include "test.h"  
    2.   
    3. int main()  
    4. {  
    5.     print();  
    6.     return 0;  
    7. }  
    #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.   
    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]$   
    [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.   
    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]$   
    [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.   
    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. }  
    #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, 我就不再过多介绍了。

  • 相关阅读:
    卡牌分组
    css字体样式+文本样式
    jQuery---on注册事件的2种方式
    css3神奇的背景控制属性+使用颜色过渡实现漂亮的渐变效果
    js Dom为页面中的元素绑定键盘或鼠标事件
    ES6中Set和WeakSet
    Vue之计算属性Computed和属性监听Watch,Computed和Watch的区别
    JS数据类型和堆栈+变量比较和值的复制+参数传递和类型检测
    复习node中加载静态资源--用express+esj
    种花问题
  • 原文地址:https://www.cnblogs.com/baiduboy/p/6048113.html
Copyright © 2011-2022 走看看