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

que*_*en3 11 c++ linux ubuntu gcc 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
Run Code Online (Sandbox Code Playgroud)

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

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

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

Emp*_*ian 13

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

正确.

但是,这些变量不会在加载的模块中使用 - 仅在加载器模块本身中使用.

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

readelf -l /path/to/foo.so | grep TLS
Run Code Online (Sandbox Code Playgroud)

可能是什么原因?

该模块正在使用-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代码.

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

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

正确.