2014年4月14日月曜日

weakシンボルに時間をとられた

waekシンボル

ceil関数からを調べていたら
cuomo@karky7 ~ $ nm -D /lib64/libm-2.17.so | grep ceil
000000000001a810 i ceil
0000000000030220 i ceilf
0000000000039a70 W ceill
cuomo@karky7 ~ $
ceil関数を調べていてnmコマンドのWをみて、「これ何だっけ?」と半分忘れかかっていたので脱線...
weakシンボルとは書き換え可能な変数、または関数名(関数のエントリアドレス)で、同名称が非weakシンボルで名前解決される場合はそちらが利用される位しか覚えていませんがあってるかどうかわからない。 でこんな感じ、
int main ()
{
  test();
  return 0;
}
#include 
#include 
extern long double ceill(long double x) __attribute__ ((weak));

void test(void)
{
  if (ceill) {
    printf("%Lf\n", ceill(15000 * 1.08));
  } else {
    printf("ceillなんて実装してねぇし\n");
  }
}

ビルド方法


ceil.so共有ライブラリを作成し、それをmain.cへリンクさせる
cuomo@karky7 ~ $ gcc -fPIC -shared -o ceil.so ceil.c
cuomo@karky7 ~ $ gcc main.c ./ceil.so
これを普通に実行してみると
cuomo@karky7 ~ $ ./a.out
ceillなんて実装してねぇし
cuomo@karky7 ~ $
これはceill関数にリンクできていないから呼び出ない、これをこうすると
cuomo@karky7 ~ $ LD_PRELOAD=/lib64/libm.so.6 ./a.out
16201.000000
cuomo@karky7 ~ $
LD_PRELOADでlibmをしてするとちゃんとceillがリンクされて実行できる。

まとめると


GCC GNU拡張のアトリビュート__attribute__でweekを使うと、リンク時に-lmを指定しなくてもリンクできるようになる。
extern long double ceill(long double x) __attribute__ ((weak));
もしこれを書かないと、-lmで明示的にリンクが必要になる
cuomo@karky7 ~ $ gcc -fPIC -shared -lm -o ceil.so ceil.c
さらに、実行時に名前解決できない場合、そのシンボルが0で初期化されて、コード(a.out)自体は実行が可能になる、そうじゃないと実行時のリンクエラーで、コード(a.out)の実行ができない。 という、よくわからない説明ですが、そういう風になっていると思います。

0 件のコメント:

コメントを投稿