9

ここでの答えは、 __attribute__((constructor)) が静的初期化後に呼び出されず、宣言順に呼び出されることを示しています。

では、すべてのデータが初期化されたときに呼び出されることが保証されていない場合、その目的は何ですか? Foo コンストラクターに ((constructor)) コードを含めることもできます。

私が探しているのは、共有ライブラリで、すべての静的データが初期化され、静的コンストラクターが呼び出された後に実行されるコードを持つ方法です。DllMain; の代わりとして __attribute__((constructor)) を推奨している人を見ました。一部の静的データがまだ初期化されていない可能性があるため、これは間違っていることがわかります。

もちろん、単一のファイル (コンパイル単位) では、静的を配置できます。しかし、典型的なプログラムにはたくさんのファイルがあります。共有ライブラリ内の他のすべての statics が初期化された後に、1 つのファイル内の ((constructor)) が確実に呼び出されることを保証する方法はありますか?

静的初期化 (コンストラクター、オブジェクトなど) を含むファイルを gcc コマンド ラインの末尾に配置すると、次のようになります。

g++ -shared -fPIC source1.o source2.o MyLastInitChance.o

このファイルの静的コンストラクターは最後に呼び出されることが保証されていますか? 実験したところ、ソースファイルの順序を変更すると、printfs の順序が変更されました。しかし、それはどこかで指定されており、コンパイルシステム/コンピューター間で同じであることが保証されていますか?

たとえば、引用:

リンク時に、gcc ドライバーはすべての再配置可能ファイルの直前に crtbegin.o を配置し、すべての再配置可能ファイルの直後に crtend.o を配置します。©

私が理解していることから、上記の引用は、リンカーに渡される .o ファイルの順序が静的初期化の順序を定義することを意味します。私は正しいですか?

もう 1 つの興味深い解決策は、静的初期化を調整する GCC プラグインを作成することです (たとえば、コードを .ctors セクションに追加するなど)。しかし、これはおそらく誰かが拡張できるアイデアにすぎません。

もう 1 つの可能な解決策をここに示します。つまり、外部のビルド後ツールを使用して、実行可能ファイル (ライブラリ) 内の .ctors エントリを並べ替えることができます。しかし、私は ELF 形式の専門家ではありません。これが可能であり、この方法で .so ファイルを微調整するのに十分簡単かどうか疑問に思います。

私が興味を持っているのは、特定の問題を解決すること、または解決できないことを証明することです (少なくとも、上記の解決策が機能しない理由)。

4

4 に答える 4

13

のリンカースクリプトを使用してみてくださいldあなたはここでそれについてもっと読むことができます、しかし私はあなたが探しているものは

.ctors : { *(SORT(.ctors)) MyLastInitChance.o(SORT(.ctors)) }
.dtors : { *(SORT(.dtors)) MyLastInitChance.o(SORT(.dtors)) }

SECTIONS{...}ブロックで。これにより、セクションが再配置.ctorsされ、提供されたファイルがそのコンストラクターを最後のコンストラクターとして呼び出すようになります。明らかに、自分で解決策が必要な場合は、より高度な解決策も利用できます;)

ヒント:独自のリンクスクリプトを作成するのは面倒です。使用済みリンクスクリプトを出力して変更するldのオプションを使用します。次に、 switch--verboseを使用してリンクスクリプトを追加します。-T

于 2012-06-25T23:40:23.267 に答える
2

このグローバルに「初回使用時の構築」パターンを実装できますか?

例えば

Magic& gMagic()
{
    static Magic magic;
    return magic;
}

すべての通常の静的 ctor の後、通常のコードがそれを必要とする前にビルドされます。

于 2012-06-26T19:48:10.717 に答える
2

attribute ((constructor))__の最大の利点は、各ブロックに関連付けられた優先順位であり、特にあなたのケースに役立ちます。

データハザードを持つ 2 つのコード ブロックがあります (1 つのセットを最初に実行する必要があります)。これは、単一の静的ブロックでは実現できません。1 つの静的ブロックと 1 つの属性((constructor))__ を使用しても、順序に関する混乱のため、問題は解決しません。

この問題に対処する最善の方法は、2 つの異なる優先度を持つ 2 つの属性((constructor))__ を用意することです。既存の静的初期化ブロックを高い優先度 (0) に移動し、他のコード ブロックを低い優先度に移動します。

于 2012-06-22T17:51:14.813 に答える
2

これを参照してください: http://gcc.gnu.org/ml/gcc-help/2011-05/msg00220.htmlと答えhttp://gcc.gnu.org/ml/gcc-help/2011-05/msg00221 .html

特に回答からの引用:

init_priority 属性を持つすべてのオブジェクトは、init_priority 属性を持たないオブジェクトよりも前に構築されます。

実際には約であり、約では__attribute__((init_priority))ありません__attribute__((constructor))が、実際にはどちらもgccとgnuリンカで同じコードを使用していると思います。最初は単に C++ オブジェクトに対応します。つまり、コンストラクタ/デストラクタを呼び出します。後者は、特定の関数をコンストラクタまたはデストラクタとしてマークすることに関するものです。

私見、__attribute__((constructor))主にC++ではなくCのために存在します。

于 2012-06-22T19:23:53.473 に答える