linuxにおけるnmコマンドの概要【回転】



(変換元:https://blog.csdn.net/stpeace/article/details/47089585)
nmはni maの略語ではなく、もちろんni meiの略語ではなく、namesの略語であり、nmコマンドは主にいくつかのファイルのシンボル(はっきり言えばいくつかの関数やグローバル変数など)をリストするために使用されます.では、一緒に見てみましょう.
       test.hは、
void print();

      test.cは:
#include 
#include "test.h"
 
void print()
{
    printf("rainy days
"); }

       main.cは:
#include "test.h"
 
int main()
{
    print();
    return 0;
}

では、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がターゲットファイルと実行可能ファイルを読み取ることができるかどうかを確認します.
 
 

[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関数などの関数が得られることがわかります.
[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を以下に変更する.

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

次に、a.outをnmで解析します(ただし、nmコマンドのみの場合、デフォルトではa.outは処理するファイルです):
[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は局所変数であり,nmは見えないため,cccは存在しない.上には「good」が見えないのに気づくべきだ.なぜだろうか.nmは「good」ではなくszTestを見るために使われているからです.忘れないでください.私たちが前に紹介したstrings命令は、次のようにします.
[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さん、私はもうあまり紹介しません.