无法再使用静态TLS加载任何对象
我有一个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
etc),我很好奇为什么它不能在 几乎 相同的系统上工作。
回答:
我怀疑这是由于使用__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
对象使用__thread
到foo.so
,然后foo.so
得到initial-exec
了 所有
的TLS的。
那么,为什么会引起问题-因为如果使用initial-exec,则tls变量的数量是有限的(因为它们不是动态分配的)?
正确。
以上是 无法再使用静态TLS加载任何对象 的全部内容, 来源链接: utcz.com/qa/431641.html