nm コマンドは、オブジェクト ファイルまたは実行可能ファイルで使用されているシンボルに関する情報を提供します。
「nm」コマンドが提供するデフォルトの情報は次のとおりです:
- シンボルの仮想アドレス
- 記号の種類を表す文字。文字が小文字の場合、シンボルはローカルですが、文字が大文字の場合、シンボルは外部です
- シンボルの名前
シンボル タイプを識別する文字は、次を表します:
- あ :グローバル絶対記号。
- あ :ローカル絶対記号。
- B :グローバル bss シンボル。
- b :ローカル bss シンボル。
- D :グローバル データ シンボル。
- d :ローカル データ シンボル。
- f :ソース ファイル名の記号。
- L :グローバル スレッド ローカル シンボル (TLS)。
- l :静的スレッド ローカル シンボル (TLS)。
- T :グローバル テキスト シンボル。
- t :ローカル テキスト シンボル。
- う :未定義のシンボル。
このリストはすべてを網羅しているわけではありませんが、いくつかの重要なシンボル タイプが含まれていることに注意してください。詳細については、このユーティリティのマニュアル ページを参照してください。
「nm」ユーティリティを使用するデフォルトの方法は次のとおりです:
$ nm <object file or executable name>
実行可能ファイル名が指定されていない場合、nm はその名前を「a.out」と見なします。
このユーティリティに関する基本的な考え方からすると、なぜこの情報が必要なのか疑問に思われるかもしれません。
さて、多くの異なるオブジェクト ファイルで構成された実行可能ファイルがあるとします。ここで、コードのコンパイル中に、リンカーが未解決のシンボル「temp」に関するエラーを出したとします。コードが大きすぎて多くのヘッダーが含まれている場合、シンボル「temp」がコード内のどこにあるかを見つけるのは悪夢になります。このユーティリティが助けになるのはここです。いくつかの追加オプションを使用すると、このユーティリティはシンボルが見つかったファイルも提供します。
これで、nm ユーティリティに関する基本的な考え方ができました。いくつかの実用的なコマンドを通して、このユーティリティの使用法を理解しましょう.
1.シンボルを参照するオブジェクト ファイルを表示
次のコマンドは、現在のディレクトリにあるシンボル「func」を参照するすべてのオブジェクト ファイルを表示します
$ nm -A ./*.o | grep func ./hello2.o:0000000000000000 T func_1 ./hello3.o:0000000000000000 T func_2 ./hello4.o:0000000000000000 T func_3 ./main.o: U func ./reloc.o: U func ./reloc.o:0000000000000000 T func1 ./test1.o:0000000000000000 T func ./test.o: U func
-A フラグを使用して、ファイル名とその他の情報を表示することに注意してください。そのため、シンボル「func」が使用されているすべてのオブジェクト ファイルが出力されていることがわかります。これは、どのオブジェクト ファイルが特定のシンボルをどのように使用しているかを知りたい場合に非常に役立ちます。
2.実行可能ファイル内のすべての未定義シンボルを表示
次のコマンドは、実行可能ファイル「1」内のすべての未定義シンボルを一覧表示します
$ nm -u 1 w _Jv_RegisterClasses w __gmon_start__ U __libc_start_main@@GLIBC_2.2.5 U free@@GLIBC_2.2.5 U malloc@@GLIBC_2.2.5 U printf@@GLIBC_2.2.5
この場合、未定義のシンボルのみをリストするためにフラグ「-u」が使用されていることに注意してください。これは、コードで使用されている未定義のシンボルが実際には解決されていないか、共有ライブラリを介して実行時に解決される可能性があることを知りたい場合に非常に役立ちます。
関連トピックでは、GCC リンク プロセスがどのように機能するかについても理解する必要があります。
3.実行可能ファイル内のすべてのシンボルを表示
次のコマンドは、実行可能ファイル「namepid」内のすべてのシンボルをアドレス順に並べ替えてリストします
$ nm -n namepid w _Jv_RegisterClasses w __gmon_start__ U __libc_start_main@@GLIBC_2.2.5 U exit@@GLIBC_2.2.5 U fclose@@GLIBC_2.2.5 U fgets@@GLIBC_2.2.5 U fopen@@GLIBC_2.2.5 U fork@@GLIBC_2.2.5 U memset@@GLIBC_2.2.5 U printf@@GLIBC_2.2.5 U puts@@GLIBC_2.2.5 U signal@@GLIBC_2.2.5 U sleep@@GLIBC_2.2.5 U strchr@@GLIBC_2.2.5 U strlen@@GLIBC_2.2.5 U strncat@@GLIBC_2.2.5 U strncpy@@GLIBC_2.2.5 U system@@GLIBC_2.2.5 0000000000400778 T _init 00000000004008a0 T _start 00000000004008cc t call_gmon_start 00000000004008f0 t __do_global_dtors_aux ... ... ...
フラグ「-n」を使用すると、出力は最初に未定義のシンボルでソートされ、次にアドレスに従ってソートされることがわかります。並べ替えにより、問題をデバッグしている開発者の作業が楽になります。
4.シンボルを検索してそのサイズを表示する
次のコマンドは、シンボル「abc」を検索し、そのサイズも表示します
$ nm -S 1 | grep abc 0000000000601040 0000000000000004 B abc
したがって、フラグ -S は、シンボル「abc」のサイズに関する追加情報を表示することがわかります
5.実行可能ファイルに動的シンボルを表示する
次のコマンドは、実行可能ファイル「1」の動的シンボルを表示します。
$ nm -D 1 w __gmon_start__ U __libc_start_main U free U malloc U printf
これは、実行時に共有ライブラリによってのみ解決できるシンボルについて知りたい場合に非常に役立ちます。
6.さまざまな種類のシンボルを抽出
nm コマンドのもう 1 つの強力な機能は、さまざまな種類のオブジェクト ファイル形式からシンボルを抽出できることです。通常、Linux では、「a.out」または ELF 形式のオブジェクトまたは実行可能コードがありますが、オブジェクトまたは実行可能コードが他の形式の場合、nm はフラグ「–target」も提供します。
7. nm 出力の形式を変更する
デフォルトでは、nm によって表示される出力の形式は bsd タイプです。フラグ -f を使用してフォーマットを変更できます。次のコマンドは、nm コマンドの出力を posix スタイルで表示します。
$ nm -u -f posix 1 _Jv_RegisterClasses w __gmon_start__ w __libc_start_main@@GLIBC_2.2.5 U free@@GLIBC_2.2.5 U malloc@@GLIBC_2.2.5 U printf@@GLIBC_2.2.5 U
同様に、出力を systemV スタイルにしたい場合は、「-f sysv」を使用できます。
8.実行可能ファイルの外部シンボルのみを表示
次のコマンドは、実行可能ファイル内の外部シンボルのみを一覧表示します
$ nm -g 1 0000000000400728 R _IO_stdin_used w _Jv_RegisterClasses 0000000000600e30 D __DTOR_END__ 0000000000601030 A __bss_start 0000000000601020 D __data_start 0000000000601028 D __dso_handle w __gmon_start__ 0000000000400640 T __libc_csu_fini 0000000000400650 T __libc_csu_init ...
フラグ -g を使用すると、外部シンボルのみの出力が有効になることに注意してください。これは、外部シンボルを特別にデバッグする際に便利です。
9. nm 出力をシンボル サイズで並べ替える
次のコマンドは、シンボルのサイズで出力を並べ替えます
$ nm -g --size-sort 1 0000000000000002 T __libc_csu_fini 0000000000000004 R _IO_stdin_used 0000000000000004 B abc 0000000000000084 T main 0000000000000089 T __libc_csu_init
フラグ –size-sort は、サイズに関して出力をソートすることに注意してください。すでに説明したように、-g は外部シンボルのみを表示するために使用されます。
10.ファイルで nm オプションを指定する
nm のもう 1 つの重要な機能は、ファイルからコマンド ライン入力を取得できることです。ファイル内のすべてのオプションを指定し、ファイル名を nm コマンドに指定すると、あとは自動的に実行されます。たとえば、次のコマンドでは、nm ユーティリティはファイル「nm_file」からコマンド ライン入力を読み取り、出力を生成します
ファイル名を指定する場合、記号「@」が必要であることに注意してください。
$ nm @nm_file 0000000000000002 T __libc_csu_fini 0000000000000004 R _IO_stdin_used 0000000000000004 B abc 0000000000000084 T main 0000000000000089 T __libc_csu_init