15

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

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

dlopen: cannot load any more object with static TLS

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

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

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

4

1 回答 1

17

我怀疑这是由使用 __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编译的模块,但我根本没有设置tls-model,据我记得默认值不是initial-exec

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

因此,即使您链接一个使用into的非-fPIC对象,也会获取其所有TLS。__threadfoo.sofoo.soinitial-exec

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

正确的。

于 2013-02-22T15:26:24.107 回答