一尘不染

无法再使用静态TLS加载任何对象

linux

我有一个dlopen()用于加载其他模块的应用程序。该应用程序和模块使用gcc 4.6在Ubuntu 12.04 x86_64上构建,但适用于i386
arch。然后将二进制文件复制到具有完全相同操作系统的另一台计算机上,并且可以正常工作。

但是,如果将它们复制到Ubuntu 12.04 i386,则某些(但不是全部)模块无法加载,并显示以下消息:

dlopen: cannot load any more object with static TLS

我怀疑这是由__thread变量的使用引起的。但是,此类变量不会在加载的模块中使用-只会在加载器模块本身中使用。

有人可以提供任何其他信息吗,这是什么原因?

我正在减少__thread变量的数量并优化它们(使用-ftls-modeletc),我很好奇为什么它不能在 几乎 相同的系统上工作。


阅读 993

收藏
2020-06-07

共1个答案

一尘不染

我怀疑这是由于使用__thread变量引起的。

正确。

但是,此类变量不会在加载的模块中使用-只会在加载器模块本身中使用。

不正确 您可能没有使用__thread自己,但是您静态链接到模块中的某些库 正在 使用它们。您可以通过以下方式进行确认:

readelf -l /path/to/foo.so | grep TLS

可能是什么原因?

该模块正在使用-ftls-model=initial-exec,但应该正在使用-ftls-model=global- dynamic。这种情况最常发生在链接到的(某些)代码foo.so没有构建时-fPIC

将非-fPIC代码链接到共享库在上是不可能的x86_64,但在上是允许的ix86(这会导致许多细微的问题,例如此问题)。

更新:

我有1个模块在没有-fPIC的情况下编译,但是据我所知,默认值不是initial-exec,所以我根本没有设置tls-model

  • 每个ELF映像(可执行或共享库)只能有一个tls模型。
  • TLS模型默认initial-exec为非-fPIC代码。

因此,如果您链接甚至一个非-fPIC对象使用__threadfoo.so,然后foo.so得到initial-exec所有
的TLS的。

那么,为什么会引起问题-因为如果使用initial-exec,则tls变量的数量是有限的(因为它们不是动态分配的)?

正确。

2020-06-07