您的位置:首页 > 运维架构 > Linux

linux中的nm命令简介---转载

2018-02-07 16:51 183 查看
版权声明:本文为博主原创文章,转载时请务必注明本文地址, 禁止用于任何商业用途, 否则会用法律维权。 http://blog.csdn.net/stpeace/article/details/47089585

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

  

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

       test.h为:

[cpp] view
plain copy

void print();  

      test.c为:

[cpp] view
plain copy

#include <stdio.h>  

#include "test.h"  

  

void print()  

{  

    printf("rainy days\n");  

}  

       main.c为:

[cpp] view
plain copy

#include "test.h"  

  

int main()  

{  

    print();  

    return 0;  

}  

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

[plain] view
plain copy

[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能否读取目标文件和可执行文件:

[plain] view
plain copy

[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函数。

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

[plain] view
plain copy

[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改为:

[cpp] view
plain copy

#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为其要处理的文件):

[plain] view
plain copy

[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命令可干这事, 如下:

[plain] view
plain copy

[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, 我就不再过多介绍了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: