2013年2月24日日曜日

[C]C ソースと C++ ソースのリンクの違い

nm コマンド
リンクの様子を確認する
$ nm hoge.o > hoge.nmdmp

objdump コマンド
オブジェクトファイルのシンボルをリスト表示する
$ objdump -x hoge.o > hoge.dmp

c++filt コマンド
オブジェクトファイルの情報を表示する
$ c++filt symbol

mangling された symbol を解読する
C++ では同じ名前を持つ関数名が複数存在することが可能なので、リンク時に適切な関数と結合できるよう関数名にラベルを埋め込んでシンボル名を作成する。この動作を mangling (マングリング) という。
  1. ソースコード準備 & コンパイル
    呼び出し元 C++ ソースコード
    Example: test.cpp
    #include <stdio.h>
    #include "libtest.h"
    
    int main(void)
    {
      lib_function("Hogehoge");
    
      return 0;
    }
    
    $ g++ test.cpp -L. -ltest
    /tmp/ccCXPMsT.o(.text+0x19): In function `main':
    : undefined reference to `lib_function(char*)'
    collect2: ld はステータス 1 で終了しました
    
  2. nm コマンドにより各オブジェクトファイル内のシンボルを確認する
    $ nm libtest.a
    
    libtest.o:
    00000000 T lib_function
             U printf
    
    $ g++ -c test.cpp -o test.o
    $ nm test.o
             U _Z12lib_functionPc
             U __gxx_personality_v0
    00000000 T main
    
    libtest.o では lib_function というシンボル名で定義されているが、test.cpp 内では mangling により _Z12lib_functionPc というシンボル名に変更されている
  3. このシンボル名を c++filt により解読してみる
    $ c++filt _Z12lib_functionPc
    lib_function(char*)
    
    すなわち _Z12lib_functionPc というシンボル名になっているが実態は lib_function(char *) というものに紐付けされている。
  4. libtest.h にある lib_function の関数宣言を以下のように C 記述であると明記する
        extern "C" int lib_function(char *str);
    
    test.cpp から生成したオブジェクトファイルのシンボル名は以下のようになる
        $ g++ -c test.cpp -o test.o
        $ nm test.o
                 U __gxx_personality_v0
                 U lib_function
        00000000 T main
    
    ちなみに gcc でコンパイルすると
        $ gcc test.cpp -L. -ltest
        /tmp/ccYsLSPi.o(.eh_frame+0x11): undefined reference to `__gxx_personality_v0'
        collect2: ld はステータス 1 で終了しました
    
    となり __gxx_personality_v0 が見つからないとエラーがでるので g++ でコンパイルする必要あり。

0 件のコメント:

コメントを投稿