マングリング
名前マングリング(名前修飾)
name mangling
コンパイラ が関数名を一意に識別するために関数名に変更を加えること
登場した経緯
一般的に、コンパイル型言語 では 分割コンパイル がサポートされている
分割コンパイル時、リンカ は オブジェクトファイル 同士を結びつける役割(リンク)を担う
どのオブジェクトファイルを結びつけるかは、名前が一致するかだけで判断している(名前解決)
そのため、C では関数や変数はグローバルな 名前空間 で管理され、名前が一意であることが求められる
(この結果、C 言語のライブラリではすべての関数に接頭辞を付けるのが慣習となった)
e.g. lib1_process と lib2_process
しかし、C++ では オーバーロード や名前空間などの新機能が導入されたことで、この方法では対応できなくなった
e.g.
code:cpp
namespace ns1 {
int32_t add(int32_t a, int32_t b) { return a+b; }
int64_t add(int64_t a, int64_t b) { return a+b; }
}
namespace ns2 {
int32_t_add(int32_t a, int32_t b) { return a+b; }
}
これを解決するために登場したのがマングリング
マングリングでは、オーバーライド された 関数の シグネチャ や型情報を名前に エンコード して オブジェクトファイル に書き出す
これにより、リンカによる オブジェクトファイル 同士を結び付ける処理はそのままに、対応できるようになった
nm(name list)コマンド
オブジェクトファイルに対して nm コマンドを用いると、リンカが動作する対象を確認することができる
code:sh
# gcc(C)で生成したオブジェクトファイルの場合
$ nm lib.o | grep add
0000000000000000 T _add
# g++(C++)で生成したオブジェクトファイルの場合
$ nm cpp-lib.o | grep add
0000000000000000 T __Z3addii
C++ の場合の出力結果を見ると、マングリングされていることが確認できる
c++filt コマンドを用いると、マングリングされた関数名を可読な C++ のコードに戻してくれる
code:sh
$ nm cpp-lib.o | grep add | c++filt
0000000000000000 T add(int, int)
T は関数が テキストセクション(テキスト領域)に存在することを示す
参考
Effective Rust ― Rustコードを改善し、エコシステムを最大限に活用するための35項目
https://lurklurk.org/linkers/linkers.html#namemangling