この設定で問題が発生することはありますか? libgcc には、この混合リンケージを問題にする内部状態がありますか?それとも単にインライン化された関数ですか?
はいぜったいに。std::call_once
Windows/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_call
1 つの TLS でコピーに書き込まれ、別の TLS でコピーから読み取られます。その後呼び出しを試みると__once_call
、null ポインターの逆参照が発生します。
上記はデバッグ調査の結果であり、意図的に作成したものではありません。あなたの経験は簡単かもしれませんし、難しいかもしれません。したがって、要約すると、はい、静的および動的の両方で libgcc をリンクすると、絶対に問題が発生する可能性があります。