6

私のアプリは多くの共有ライブラリを取り込みます。一部は、libgcc_s.so をプルする libstdc++.so をプルする C++ で記述されています。さらに、プレーン C で記述され、-static-libgcc でリンクされているものもあります。

そのため、複数の共有ライブラリ内で静的にリンクされた libgcc のビットと、実行時に libgcc の他のビットを動的にロードする libstdc++ があります。

Q1: この設定で問題は発生しますか? libgcc には、この混合リンケージを問題にする内部状態がありますか?それとも単にインライン化された関数ですか?

Q2: アプリを古い Linux で動作させるには、libstdc++.so と libgcc_s.so を出荷し、メインの exe で rpath を使用してロードする必要があります。これは正しい方法ですか?

4

2 に答える 2

2

この設定で問題が発生することはありますか? libgcc には、この混合リンケージを問題にする内部状態がありますか?それとも単にインライン化された関数ですか?

はいぜったいに。std::call_onceWindows/MinGW で呼び出したときにプログラムがクラッシュする原因を突き止めるために、約 1 週間の終日デバッグを行いました。以下は縮小されたテスト ケースです。

mybin.cpp:

#include <pthread.h>
#include <mutex>
#include <iostream>

extern "C" int* getVar();

void print()
{
    std::cout << "Hello, var=" << *getVar() << "\n";
}

int main()
{
    pthread_key_t key;
    // Create first key, which will occupy the zero value, so that
    // __emutls_get_address will get a nonzero one when initializing emutls_key
    // (otherwise due to some C+pthread symmetries we'll not get the crash).
    pthread_key_create(&key, nullptr);

    std::once_flag f;
    // Crash
    std::call_once(f, print);
}

mylib.c:

// Make gcc emit some calls to __emutls_get_address to import
// libgcc implementing this function
static __thread int someVar;
int* getVar(void)
{
    if(!someVar)
        someVar=5;
    return &someVar;
}

Makefile:

test: libmylib.dll mybin.o
    g++ mybin.o -o test -pthread -static-libgcc -L. -lmylib

libmylib.dll: mylib.c Makefile
    gcc -fPIC -shared mylib.c -o libmylib.dll

mybin.o: mybin.cpp Makefile
    g++ -c mybin.cpp -o mybin.o

ここでのクラッシュは、次の原因で発生します。std::call_once呼び出し先 (ここではprint) のアドレスをスレッド ローカル ポインター__once_callに書き込みます。そのアドレスは への呼び出しによって検出され__emutls_get_addressます。この呼び出しは から直接行われるため、静的libgcc.exeによって解決されます (上記を参照)。次に何が起こるかというと、libstdc++ はその を呼び出し、動的​​libgccからインポートされたviaのアドレスを見つけようとします。これは、libstdc++ が動的ライブラリであるためです。Makefile__once_proxy__once_call__emutls_get_address

その結果emutls_key、libgcc の静的グローバル変数である は、libgcc のコピーごとに 2 回初期化され (pthread_key_create事前に呼び出される場合)、__once_call1 つの TLS でコピーに書き込まれ、別の TLS でコピーから読み取られます。その後呼び出しを試みると__once_call、null ポインターの逆参照が発生します。

上記はデバッグ調査の結果であり、意図的に作成したものではありません。あなたの経験は簡単かもしれませんし、難しいかもしれません。したがって、要約すると、はい、静的および動的の両方で libgcc をリンクすると、絶対に問題が発生する可能性があります。

于 2020-01-28T06:41:15.627 に答える