GCC(binutils)のツールの紹介: nm&c++filt
前回の続きでBinutilsのツール群の説明をします。
今回はnmとc++filtを説明します。
これらのツールはどれも前回説明したobjdumpの一部の機能みたいなものです。
ソースコード
#include <cstdio> const static int CONST_VALUE = 100; int uninitialized_value; class SuperClass { public: virtual void print(const char *str) = 0; }; class Sub1 : public SuperClass{ public: void print(const char *str){ printf("Sub1: %s\n", str); } }; class Sub2 : public SuperClass{ public: void print(const char *str){ printf("Sub2: %s\n", str); } }; int main(void){ SuperClass *hoge = new Sub1(); printf("CONST_VALUE: %p\n", &CONST_VALUE); printf("uninitialized_value: %p\n", &uninitialized_value); return 0; }
コンパイルしておきます。今回はリンクまでします。
$ g++ -g test.cpp $ ls a.out test.cpp $ ./a.out CONST_VALUE: 0x8048774 uninitialized_value: 0x8049a34
nm
nmコマンドはオブジェクトの中のシンボルを一覧表示します。
$ nm a.out # 一部削ってます 08049898 d _DYNAMIC 08049984 d _GLOBAL_OFFSET_TABLE_ 0804873c R _IO_stdin_used w _Jv_RegisterClasses 08048774 r _ZL11CONST_VALUE 08048654 W _ZN10SuperClassC2Ev 08048638 W _ZN4Sub15printEPKc 08048662 W _ZN4Sub1C1Ev 080487b8 V _ZTI10SuperClass 0804879c V _ZTI4Sub1 080487a8 V _ZTS10SuperClass 08048794 V _ZTS4Sub1 08048788 V _ZTV10SuperClass 08048778 V _ZTV4Sub1 080499c0 V _ZTVN10__cxxabiv117__class_type_infoE@@CXXABI_1.3 08049a00 V _ZTVN10__cxxabiv120__si_class_type_infoE@@CXXABI_1.3 U _Znwj@@GLIBCXX_3.4 080485d4 T main U printf@@GLIBC_2.0 08049a34 B uninitialized_value
2列目に表示されるシンボルの意味は以下の通りです。
大文字は外部公開されるシンボルで、小文字はされないシンボルとなります。
- A 絶対値。リンク後も値が変わらない。
- B,b 実初期化データ(BSS)
- D,d 初期化済みデータ(Dataセクション)
- R,r リードオンリー
- T,t コード(Textセクション)
- U 未定義シンボル
- V,v ウィークオブジェクト。
- W,w ウィークシンボル。
ソースコードの実行結果と比較してみると、uninitialized_valueとCONST_VALUEのアドレスが一致していることがわかります。
c++filt
c++ではシンボル名が一意になるように名前マングルされるため、ぱっと見では何の関数かよくわかりません。
そこでデマングルするためのツールがこのc++filtです。
単純な使い方は引数にデマングルしたいシンボル名を渡すだけですが、標準入力から渡すこともできます。
$ nm a.out | c++filt 08049898 d _DYNAMIC 08049984 d _GLOBAL_OFFSET_TABLE_ 0804873c R _IO_stdin_used w _Jv_RegisterClasses 08048774 r CONST_VALUE 08048654 W SuperClass::SuperClass() 08048638 W Sub1::print(char const*) 08048662 W Sub1::Sub1() 080487b8 V typeinfo for SuperClass 0804879c V typeinfo for Sub1 080487a8 V typeinfo name for SuperClass 08048794 V typeinfo name for Sub1 08048788 V vtable for SuperClass 08048778 V vtable for Sub1 080499c0 V vtable for __cxxabiv1::__class_type_info@@CXXABI_1.3 08049a00 V vtable for __cxxabiv1::__si_class_type_info@@CXXABI_1.3 U operator new(unsigned int)@@GLIBCXX_3.4 080485d4 T main U printf@@GLIBC_2.0 08049a34 B uninitialized_value
この例では、nm自体にデマングルの機能があるためわざわざc++filtを使う必要はないです
$ nm -C a.out
シンボル表をどういったケースで使うかをぱっと思いつかなかったので今回は割愛します。
実際にはデバッグなどで関数のアドレスを知りたいときとかにobjdumpではなくシンボル一覧から探したりすることは結構あります。