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

时间:2013-02-15 09:56:20

标签: c++ linux gcc ubuntu dlopen

我有一个使用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-model等),我只是好奇为什么它不能在几乎相同的系统上运行。

1 个答案:

答案 0 :(得分:11)

  

我怀疑这是由__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模型。
  • initial-exec代码的TLS模型默认为-fPIC

如果您将一个使用-fPIC的非__thread对象链接到foo.so,那么foo.so将获得initial-exec all < / T>的TLS。

  

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

正确。