6

我的应用程序引入了许多共享库。有些是用 C++ 编写的,它引入了 libstdc++.so,它引入了 libgcc_s.so。还有一些是用纯 C 编写的,并与 -static-libgcc 链接。

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

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

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

4

2 回答 2

2

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

绝对没错。我刚刚花了大约一周的全天调试时间来找出导致我的程序在调用std::call_onceWindows/MinGW 时崩溃的原因。这是一个简化的测试用例:

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,因此它由静态libgcc 解决(见Makefile上文)。接下来发生的是 libstdc++ 调用它的__once_proxy,然后它试图找到__once_callvia的地址,该地址__emutls_get_address是从动态libgcc 导入的,因为 libstdc++ 是一个动态库。

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

以上只是我调试调查的结果,不是我故意制作的。你的经历可能更容易或更难。所以,总而言之,的,静态和动态链接 libgcc绝对会导致麻烦。

于 2020-01-28T06:41:15.627 回答
0

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

绝对不是。静态链接库在程序内部并入,就好像在程序自己的结构中实现一样。
来自维基百科:(我的重点)

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

看到这个支持的想法
至于您评论中的崩溃,这很可能是一个错误。

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

不,只是内联函数。

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

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

于 2015-06-29T15:32:29.590 回答