我有一个dlopen()用于加载其他模块的应用程序。该应用程序和模块使用gcc 4.6在Ubuntu 12.04 x86_64上构建,但适用于i386 arch。然后将二进制文件复制到具有完全相同操作系统的另一台计算机上,并且可以正常工作。
dlopen()
但是,如果将它们复制到Ubuntu 12.04 i386,则某些(但不是全部)模块无法加载,并显示以下消息:
dlopen: cannot load any more object with static TLS
我怀疑这是由__thread变量的使用引起的。但是,此类变量不会在加载的模块中使用-只会在加载器模块本身中使用。
__thread
有人可以提供任何其他信息吗,这是什么原因?
我正在减少__thread变量的数量并优化它们(使用-ftls-modeletc),我很好奇为什么它不能在 几乎 相同的系统上工作。
-ftls-model
我怀疑这是由于使用__thread变量引起的。
正确。
但是,此类变量不会在加载的模块中使用-只会在加载器模块本身中使用。
不正确 您可能没有使用__thread自己,但是您静态链接到模块中的某些库 正在 使用它们。您可以通过以下方式进行确认:
readelf -l /path/to/foo.so | grep TLS
可能是什么原因?
该模块正在使用-ftls-model=initial-exec,但应该正在使用-ftls-model=global- dynamic。这种情况最常发生在链接到的(某些)代码foo.so没有构建时-fPIC。
-ftls-model=initial-exec
-ftls-model=global- dynamic
foo.so
-fPIC
将非-fPIC代码链接到共享库在上是不可能的x86_64,但在上是允许的ix86(这会导致许多细微的问题,例如此问题)。
x86_64
ix86
更新:
我有1个模块在没有-fPIC的情况下编译,但是据我所知,默认值不是initial-exec,所以我根本没有设置tls-model
initial-exec
因此,如果您链接甚至一个非-fPIC对象使用__thread到foo.so,然后foo.so得到initial-exec了 所有 的TLS的。
那么,为什么会引起问题-因为如果使用initial-exec,则tls变量的数量是有限的(因为它们不是动态分配的)?