为什么访问静态链接的 dlopen 加载的库中的线程本地存储(TLS)会导致段错误?

为什么访问静态链接的 dlopen 加载的库中的线程本地存储(TLS)会导致段错误?

我有一个与 gcc 链接的 exe -static,用于dlopen加载共享库。该库尝试访问线程本地存储 (TLS) 中的变量。当我们尝试访问 TLS 变量时,运行应用程序会出现段错误。删除该-static标志可避免段错误。

虽然这种用法不常见,但实际上有什么不对吗?

这样做的目的是允许静态链接的 exe 在运行时选择性地加载插件(当其依赖项存在时),但默认情况下无需依赖这些依赖项即可运行。对 TLS 的需求源于它在 C++ 异常处理中的使用(因此我通常无法通过修改共享库本身的编译方式来解决这个问题)。

==> main.c <==
#include <dlfcn.h>

int main()
{
    void* lib = dlopen("./libusetls.so", RTLD_NOW);
    typedef int func_t();
    func_t* function = dlsym(lib, "function");
    return function();
}

==> usetls.c <==
#include <stdio.h>

int function()
{
  static __thread int value = 0;
  return value;
}

==> makefile <==
 gcc -o main main.c -ldl -g -static

usetls.o: usetls.c makefile
 gcc -c -fPIC -o usetls.o usetls.c -g

libusetls.so: usetls.o makefile
 gcc -shared -fPIC -Wl,-soname,libusetls.so -o libusetls.so usetls.o -lc

clean:
 rm main usetls.o libusetls.so

相关内容