如何确定 Linux 上的最大静态 TLS(线程本地存储)块大小?

问题描述 投票:0回答:1

问题

尝试运行此代码

if (!dlopen("../lib/libMy.so", RTLD_NOW)) {
    perror("dlopen FAILED!");
    return 1;
}

导致此 TLS(线程本地存储)错误:

无法在静态 TLS 块中分配内存

解决方案

转储线程局部存储部分

.tbss
(静态和非静态未初始化线程局部变量)显示
Tls_ErrorStruct
大小为600字节(0x258),
Tls_tv
为1600字节(0x640),总共2200个TLS字节:

$ objdump -C -t ../lib/libMy.so | grep -F '.tbss'

00000000000008e8 l       .tbss  0000000000000008              runtime.tlsg
0000000000000010 l       .tbss  0000000000000001              __tls_guard
0000000000000688 l       .tbss  0000000000000001              __tls_guard
...
0000000000000690 g       .tbss  0000000000000258              Tls_ErrorStruct
...
0000000000000018 g       .tbss  0000000000000640              Tls_tv

为了修复块错误,这些

thread_local
变量被减少到约 600 字节。
dlopen
现在成功了。

问题

我不确定如何找到动态链接器线程本地存储块大小,但确实找到了可能的参考here

/* Size of the static TLS block.  Giving this initialized value
   preallocates some surplus bytes in the static TLS area.  */
size_t _dl_tls_static_size = 2048;
  1. 是否有linux工具或一些C++方法来确定最大值 线程本地存储块大小?

  2. 有没有办法计算线程本地存储的总使用量 对于共享对象以确保它在系统的限制之内?

c++ linux gcc dlopen
1个回答
1
投票

从技术上讲,这不是一个答案,因为我不想尝试这个,只是对可能的修复方案的一个想法。是的,当涉及到不影响我的事情时,我就是这么懒。

对于初学者来说,虽然我们在

pthread
tls API 中拥有有限数量的“线程本地键”,但该 API 并未被使用,所以这并不重要。相反,Linux 使用 ELF 部分作为其线程本地存储,这没有任何限制。

您遇到的限制来自于

dlopen()
打开初始加载程序未见过的模块。现在,您发现的
_dl_tls_static_size
符号似乎可以在某种程度上处理这种情况,只需让加载程序分配更多的内存即可。但是,跟踪该符号,您会发现以下评论:

  /* That is the size of the TLS memory for this object.  The initialized
     value of _dl_tls_static_size is provided by dl-open.c to request some
     surplus that permits dynamic loading of modules with IE-model TLS.  */

这里突出的词是“IE模型”,表明可能存在其他不需要这个的“模型”。如果您查看

gcc
选项,您会发现:

-ftls-model=model

    Alter the thread-local storage model to be used (see Thread-Local Storage). The model argument should be one of ‘global-dynamic’, ‘local-dynamic’, ‘initial-exec’ or ‘local-exec’. Note that the choice is subject to optimization: the compiler may use a more efficient model for symbols not visible outside of the translation unit, or if -fpic is not given on the command line.

    The default without -fpic is ‘initial-exec’; with -fpic the default is ‘global-dynamic’.

是的,我们有一个模型

initial-exec
,它可以很容易地缩写为
IE
,这就是我们在评论中看到的。 因此,如果您可以控制此共享对象的编译方式,那么可能值得尝试
global-dynamic

© www.soinside.com 2019 - 2024. All rights reserved.