C++のマングルされたシンボルをC言語で使う
2012-05-19
C++のシンボルはマングルされている
C++では関数のオーバーロードや名前空間があるため、シンボルはマングルされ、それぞれの関数が一意に識別されるようになっています。
今回はそのマングルされたシンボルを直接利用してC++で定義された関数をC言語から呼び出してみます。
下ごしらえ
foo.ccとして次のコードを保存します。
#include <iostream>
void foo()
{
std::cout << "foo called" << std::endl;
}
コンパイルします。
$ g++ -c foo.cc
void foo()がどのようになっているか確認しましょう。
$ nm foo.o
0000000000000062 t _GLOBAL__I__Z3foov
0000000000000000 T _Z3foov
0000000000000022 t _Z41__static_initialization_and_destruction_0ii
U _ZNSolsEPFRSoS_E
U _ZNSt8ios_base4InitC1Ev
U _ZNSt8ios_base4InitD1Ev
U _ZSt4cout
U _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
0000000000000000 b _ZStL8__ioinit
U _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
U __cxa_atexit
U __dso_handle
U __gxx_personality_v0
_Z3foovが見つかります。
c++filtで確認してみましょう。
$ c++filt _Z3foov
foo()
つまり_Z3foov がマングルされたシンボルです。
次に呼び出す側のC言語のソースを用意します。
void _Z3foov();
int main()
{
_Z3foov();
return 0;
}
それではコンパイルしましょう。
$ gcc foo.o main.c
foo.o: In function `foo()':
foo.cc:(.text+0xa): undefined reference to `std::cout'
foo.cc:(.text+0xf): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<c\
har, std::char_traits<char> >&, char const*)'
foo.cc:(.text+0x14): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<c\
har, std::char_traits<char> >&)'
foo.cc:(.text+0x1c): undefined reference to `std::basic_ostream<char, std::char_traits<char> >::operator<<(std::basic_ostream<char, std::char_traits<char> >&\
(*)(std::basic_ostream<char, std::char_traits<char> >&))'
foo.o: In function `__static_initialization_and_destruction_0(int, int)':
foo.cc:(.text+0x45): undefined reference to `std::ios_base::Init::Init()'
foo.cc:(.text+0x4a): undefined reference to `std::ios_base::Init::~Init()'
foo.o:(.eh_frame+0x12): undefined reference to `__gxx_personality_v0'
collect2: ld はステータス 1 で終了しました
あれれ、リンクエラーが発生しました。
g++でコンパイルしたソースをgccでリンクする場合、libstdc++を明示的に指定してやる必要があります。
$ gcc -lstdc++ foo.o main.c
コンパイル完了。
実行してみましょう。
$ ./a.out
foo called
無事に呼ばれていることがわかります。
まとめ
今回はマングルされたシンボルを直接利用してC++で定義された関数をC言語から呼び出す方法を紹介しました。
ご質問等、何かありましたらこちらへ。