2012-02-27 9 views
9

私の共有ライブラリでは、ロード時に特定の初期化を行う必要があります。私がGCC属性__attribute__ ((constructor))で関数を定義すると、それは機能しません。つまり、共有ライブラリをリンクしているプログラムがロードされたときに呼び出されません。共有ライブラリのコンストラクタが動作しない

機能名を_init()に変更すると機能します。明らかに_init()_fini()の機能の使用は現在not recommendedです。

なぜ__attribute__ ((constructor))がうまくいかないのですか?これは、Linux 2.6.9、gccバージョンである3.4.6

編集:.soのを構築するための

#include <stdio.h> 

int smlib_count; 

void __attribute__ ((constructor)) setup(void) { 
    smlib_count = 100; 
    printf("smlib_count starting at %d\n", smlib_count); 
} 

void smlib_count_incr() { 
    smlib_count++; 
    smlib_count++; 
} 

int smlib_count_get() { 
    return smlib_count; 
} 

例えば

、のライブラリのコードは、この次のようであるとしましょう私は、次の操作を行います

gcc -fPIC -c smlib.c 
ld -shared -soname libsmlib.so.1 -o libsmlib.so.1.0 -lc smlib.o 
ldconfig -v -n . 
ln -sf libsmlib.so.1 libsmlib.so 

の.soは私がを更新する標準的な場所の一つではありませんので、を開き、別のプログラムから.soをリンクします。コンストラクタは呼び出されません。私が_init()に変更すると動作します。

+0

これは、関数定義で属性文字列を配置する場所と関連があります。あなたの中にはどこがありますか?私はそれのように動作するものを持っています: 'void __attribute__((コンストラクタ))コンストラクタ(){...}'。 'void'の後で' constructor() 'の前にあることに注意してください。 –

+1

答えはありませんが、共有ライブラリコンストラクタは、 'main'が入力される前にプログラムの初期状態を混乱させるため、一般的に有害であると考えられます。最も悪名高い例は、OpenALです。これは、ALSAライブラリ/デバイスの状態で、アプリケーションが後でALSAデバイスを開くのを妨げるような状態になってしまいました(少なくとも一度は修正されていますが、わかりません)。適切なライブラリは、グローバルな状態を避けるために最善を尽くすべきであり、絶対に必要な場合は、ctorsではなく最初のライブラリ呼び出しで遅延初期化を使用する必要があります。 –

+0

@Dan Fego、上記で提案したプレースメントを含め、さまざまなプレースメントを試しました。それでも動作しません。 – Manohar

答えて

2

さて、私はこれを見てきましたが、あなたの中間gccステップ(-cを使用している)が原因で問題が発生しているようです。ここに私が見ているものの私の解釈があります。

あなたはsetup().oとしてコンパイルすると、(あなたが.soとしてコンパイルしていないことから、それは気にしません)gccはただ通常の関数として扱います。次に、ldはELFの動的セクションに_init()またはDT_INITのようなものは表示されず、コンストラクタがないものとみなされます。

.o_init()にコンパイルすると、gccも通常の関数として扱われます。実際には、それは私のようにのオブジェクトファイルは、機能自体の名前を除いて同じであるように見えます!したがって、ld.oファイルを調べますが、今度は_init()という機能があり、探していると判断してコンストラクタと判断し、.soDT_INITというエントリを作成します。あなたはこのようなコンパイルと1つのステップでリンクを行う場合

最後に、:

gcc -Wall -shared -fPIC -o libsmlib.so smlib.c 

は、次に何が起こるかgccを見て、共有オブジェクトを作成するのコンテキストで__attribute__ ((constructor))を理解し、作成することですそれに応じてDT_INITエントリ。

ショートバージョン:gccを使用してコンパイルとリンクを1ステップで実行します。 -Wl,-soname,libsmlib.so.1のように、-sonameのような余分なオプションを渡す場合は、-Wl(マニュアルページを参照)を使用できます。「共有ライブラリ 『はgccの引数-nostartfiles『』または-nostdlib』でコンパイルしてはいけません

これらの引数を使用する場合は、コンストラクタ/デストラクタルーチンが実行されません(特別な場合を除き:this linkから

+0

クール..それはそれを説明します。ありがとう! – Manohar

+5

これはワンステップで行う必要はありません。それがうまくいくのは、ldではなく、リンクするためにgccを-sharedで使用することです。 – Thomas

+0

コンストラクタを持つオプションはありませんが、2つのステップ(.o、.so)がありますか? CMakeプロジェクトには必要です – dashesy

2

。措置を講じる)。

gcc/ldは、-nostdlibが使用されているときにelfヘッダーのDT_INITビットを設定しません。どちらの場合も、objdump -pをチェックしてINITセクションを調べることができます。 属性((コンストラクタ))の場合、INITセクションが見つかりません。しかし、__initの場合は、共有ライブラリのINITセクションがあります。

関連する問題