有没有办法确定Linux上的库使用的线程本地存储模型

rob*_*nce 7 linux glibc shared-libraries thread-local-storage ldd

有没有办法在Linux上查询共享库的TLS模型?(例如使用ldd或其他工具).

我在使用"initial-exec"模型加载太多库时遇到了麻烦,并且想确定哪个第三方库使用此模型(因此我可以释放一些插槽,例如通过静态链接).

这会导致错误:

 dlopen: cannot load any more object with static TLS
Run Code Online (Sandbox Code Playgroud)

看到这个问题.

Jam*_*dge 10

我自己遇到了这个错误,在调查时,我发现了一个包含以下信息邮件列表帖子:

如果链接包含IE模型访问重定位的共享对象,则该对象将设置DF_STATIC_TLS标志.根据规范,这意味着dlopen可能会拒绝加载它.

/usr/include/elf.h,我们有:

/* Values of `d_un.d_val' in the DT_FLAGS entry.  */
...
#define DF_STATIC_TLS   0x00000010      /* Module uses the static TLS model */
Run Code Online (Sandbox Code Playgroud)

因此,您需要测试是否在共享库DF_STATIC_TLSDT_FLAGS条目中设置.

为了测试,我使用线程本地存储创建了一段简单的代码:

static __thread int foo;
void set_foo(int new) {
    foo = new;
}
Run Code Online (Sandbox Code Playgroud)

然后我用两个不同的线程本地存储模型编译了两次:

gcc -ftls-model=initial-exec -fPIC -c tls.c  -o tls-initial-exec.o
gcc -shared tls-initial-exec.o -o tls-initial-exec.so

gcc -ftls-model=global-dynamic -fPIC -c tls.c  -o tls-global-dynamic.o
gcc -shared tls-global-dynamic.o -o tls-global-dynamic.so
Run Code Online (Sandbox Code Playgroud)

当然,我可以看到两个库之间的区别readelf:

$ readelf --dynamic tls-initial-exec.so

Dynamic section at offset 0xe00 contains 25 entries:
  Tag        Type                         Name/Value
...
 0x000000000000001e (FLAGS)              STATIC_TLS
Run Code Online (Sandbox Code Playgroud)

tls-global-dynamic.so版本没有DT_FLAGS条目,大概是因为它没有设置任何标志.因此,使用readelfgrep查找受影响的库创建脚本应该相当容易.

  • 非常感谢!很好的答案.我还找到了`readelf -l library | grep TLS`很有用.这表明是否存在任何线程位置存储.事实证明,任何TLS也使用DTV插槽(因此可以阻止以后的STATIC_TLS对象加载),但是如果你先加载STATIC_TLS对象,那么非intial-exec使用另一种方法而不占用插槽. (2认同)