Would this setup give me any trouble? Does libgcc have internal state that would make this mixed linkage problematic, or is it just inlined functions?
Absolutely yes. I've just spent about a week of full-day debugging to find out what caused my program to crash when calling std::call_once
on Windows/MinGW. Here's a reduced test case:
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
The crash here happens due to the following. std::call_once
writes the address of the callee (here print
) into a thread-local pointer __once_call
, the address of which is found via a call to __emutls_get_address
. This call happens directly from the .exe
, so it's resolved by the static libgcc (see the Makefile
above). What happens next is that libstdc++ calls its __once_proxy
, which then tries to find the address of __once_call
via __emutls_get_address
, which is imported from the dynamic libgcc, because libstdc++ is a dynamic lib.
The result is that emutls_key
, which is a static global variable of libgcc, gets initialized twice, per copy of libgcc (provided pthread_key_create
is called beforehand), and __once_call
gets written to the copy in one TLS and read from the copy in another TLS. The subsequent attempt to call __once_call
results in null pointer dereference.
The above is just the result of my debugging investigation, not something I crafted on purpose. Your experience might be easier or harder. So, in summary, yes, linking libgcc both statically and dynamically absolutely can cause trouble.