libgcc_s.so是否在同一进程中静态和动态链接?

时间:2015-03-26 15:54:16

标签: c++ c linux libstdc++ libgcc

我的应用程序引入了许多共享库。有些是用C ++编写的,它引入了libstdc ++。所以它引入了libgcc_s.so。还有一些是用简单的C编写的,并与-static-libgcc相关联。

所以现在我在多个共享库中静态链接了一些libgcc,并且libstdc ++在运行时动态加载libgcc的其他位。

Q1:这个设置会给我带来麻烦吗? libgcc是否具有会使这种混合链接出现问题的内部状态,或者它只是内联函数?

Q2:为了使我的应用程序能够在较旧的Linux上运行,我应该发布libstdc ++。so和libgcc_s.so并在主exe上使用rpath来加载它。这是正确的方法吗?

2 个答案:

答案 0 :(得分:2)

此设置会给我带来麻烦吗? libgcc是否具有使这种混合链接成为问题的内部状态,还是只是内联函数?

绝对可以。我刚刚花了整整一周的时间进行调试,以找出导致Windows / MinGW上的std::call_once程序崩溃的原因。这是一个简化的测试用例:

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找到。此调用直接从.exe发生,因此由 static libgcc解决(请参见上面的Makefile)。接下来发生的事情是libstdc ++调用其__once_proxy,然后它试图通过__once_call查找__emutls_get_address的地址,该地址是从 dynamic libgcc导入的,因为libstdc ++是动态库。

结果是emutls_key是libgcc的静态全局变量,每个libgcc副本被初始化两次(提供的pthread_key_create被事先调用),并且__once_call被写入到一个TLS中的副本,并从另一个TLS中读取副本。随后尝试调用__once_call会导致空指针取消引用。

以上内容只是我进行调试调查的结果,而不是我有意制作的。您的经验可能会更容易或更难。因此,总而言之,,静态地和动态地绝对地链接libgcc会会造成麻烦。

答案 1 :(得分:1)

  

这个设置会给我带来麻烦吗?

绝对不是。一个静态链接的库被内部包含在程序中,就像在程序自己的结构中一样。从Wikipedia(我的重点)

  

静态库或静态链接库是一组例程,外部函数和变量,在编译时在调用者中解析复制到目标中由编译器,链接器或绑定器应用,生成目标文件和独立可执行文件。

请参阅this supportive idea 至于评论中的崩溃,这很可能是一个错误。

  

libgcc是否具有使这种混合链接有问题的内部状态,或者它只是内联函数?

没有。只是内联函数。

  

为了使我的应用程序可以在较旧的Linux上运行,我应该发送libstdc ++。so和libgcc_s.so并在主exe上使用rpath来加载它。这是正确的方法吗?

这个问题有点建议,所以我要说我会怎么做。我会搜索libstdc ++。所以在运行时标准/默认动态链接搜索路径(可能在环境变量或某个文件中,取决于系统),如果找到,加载它。如果未找到,请加载装运的库。如果您事先知道系统没有那些动态库,那么我建议使用该程序的静态构建。