linux中的nm命令簡介
阿新 • • 發佈:2018-12-19
一般來說, 搞linux開發的人, 才會用到nm命令, 非開發的人, 應該用不到。 雖然nm很簡單, 但是還是有必要寫幾句, 聊表心意。
nm不是ni ma的縮寫, 當然, 也不是ni mei的縮寫, 而是names的縮寫, nm命令主要是用來列出某些檔案中的符號(說白了就是一些函式和全域性變數等)。 下面, 我們一起來看看。
test.h為:
void print();
test.c為:
#include <stdio.h>#include "test.h"void print(){ printf("rainy days\n");}
main.c為:
#include "test.h"int main(){ print(); return 0;}
好, 我們看看nm命令的作用效果, 如下:[[email protected] learn_nm]$ nm *nm: main.c: File format not recognizednm: test.c: File format not recognizednm: test.h: File format not recognized[[email protected] learn_nm]$
ni ma, 啥都沒有, 這說明nm對這類檔案無用。繼續看nm能否讀取目標檔案和可執行檔案:
[[email protected] learn_nm]$ lsmain.c test.c test.h[[email protected] learn_nm]$ gcc -c test.c main.c [[email protected] learn_nm]$ gcc test.o main.o[[email protected] learn_nm]$ ./a.out rainy days[[email protected] learn_nm]$ nm *a.out:08049564 d _DYNAMIC08049630 d _GLOBAL_OFFSET_TABLE_0804849c R _IO_stdin_used w _Jv_RegisterClasses08049554 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_start08049648 D __data_start08048450 t __do_global_ctors_aux08048330 t __do_global_dtors_aux080484a0 R __dso_handle w __gmon_start__0804844a T __i686.get_pc_thunk.bx08049550 d __init_array_end08049550 d __init_array_start080483e0 T __libc_csu_fini080483f0 T __libc_csu_init U [email protected]@GLIBC_2.00804964c A _edata08049654 A _end0804847c T _fini08048498 R _fp_hw08048290 T _init08048300 T _start0804964c b completed.596308049648 W data_start08049650 b dtor_idx.596508048390 t frame_dummy080483c8 T main080483b4 T print U [email protected]@GLIBC_2.0nm: main.c: File format not recognizedmain.o:00000000 T main U printnm: test.c: File format not recognizednm: test.h: File format not recognizedtest.o:00000000 T print U puts[[email protected] learn_nm]$
可以看到, 對於目標檔案和可執行檔案而言, 均可以獲得其中的函式, 如print函式。我們繼續看靜態庫和動態庫, 如下:
[[email protected] learn_nm]$ lsmain.c test.c test.h[[email protected] learn_nm]$ gcc -c test.c[[email protected] learn_nm]$ ar rcs libtest.a test.o[[email protected] learn_nm]$ gcc -shared -fPIC -o libtest.so test.o[[email protected] learn_nm]$ lslibtest.a libtest.so main.c test.c test.h test.o[[email protected] learn_nm]$ nm lib*libtest.a:test.o:00000000 T print U putslibtest.so:000014bc a _DYNAMIC00001590 a _GLOBAL_OFFSET_TABLE_ w _Jv_RegisterClasses000014a8 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 [email protected]@GLIBC_2.1.300000440 t __do_global_ctors_aux00000350 t __do_global_dtors_aux000014b8 d __dso_handle w __gmon_start__00000419 t __i686.get_pc_thunk.bx000015a4 A _edata000015ac A _end00000478 T _fini000002ec T _init000015a4 b completed.5963000015a8 b dtor_idx.5965000003e0 t frame_dummy00000420 T print U [email protected]@GLIBC_2.0[[email protected] learn_nm]$
可以看到, 我們可以從靜態庫和動態庫中獲取到函式名稱, 如print函式。好, 我們再來看看全域性變數的情形, 我們把main.c改為:
#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為其要處理的檔案):[[email protected] learn_nm]$ lsmain.c[[email protected] learn_nm]$ gcc main.c [[email protected] learn_nm]$ ./a.out [[email protected] learn_nm]$ nm a.out 08049538 d _DYNAMIC08049604 d _GLOBAL_OFFSET_TABLE_0804847c R _IO_stdin_used w _Jv_RegisterClasses08049528 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_start08049618 D __data_start08048430 t __do_global_ctors_aux08048310 t __do_global_dtors_aux08048480 R __dso_handle w __gmon_start__0804842a T __i686.get_pc_thunk.bx08049524 d __init_array_end08049524 d __init_array_start080483c0 T __libc_csu_fini080483d0 T __libc_csu_init U [email protected]@GLIBC_2.008049628 A _edata08049634 A _end0804845c T _fini08048478 R _fp_hw08048274 T _init080482e0 T _start08049630 B aaa08048394 T add0804961c D bbb08049628 b completed.596308049618 W data_start0804962c b dtor_idx.596508048370 t frame_dummy080483a2 T main08049620 D szTest[[email protected] learn_nm]$
可以看到, 不僅有add函式, 還有全域性變數aaa, bbb和szTest, 要注意, aaa是未初始化的, 所以在Bss段, 而bbb、szTest是初始化了的, 所以在Data段。 值得注意的是, 並沒有ccc, 因為ccc是區域性變數, nm看不到的。 我們還應該注意到, 在上面看不到"good", 為啥呢? 因為nm是用來看szTest而非"good"的。 別忘了, 我們之前介紹過的strings命令可幹這事, 如下:
[[email protected] learn_nm]$ lsa.out main.c[[email protected] learn_nm]$ strings a.out /lib/ld-linux.so.2__gmon_start__libc.so.6_IO_stdin_used__libc_start_mainGLIBC_2.0PTRh[^_]good[[email protected] learn_nm]$
nm命令主要列出特性檔案中的符號資訊, 具體更加詳細的用法, 請問man, 我就不再過多介紹了。