线程本地存储变量的地址

时间:2014-07-17 01:40:44

标签: linux gcc thread-local-storage

好的,说我有

__thread int myVar;

然后我将& myVar从一个线程传递到另一个线程......如果数据真的是" local",则1个线程的TLS存储可能无法映射到其他线程的地址空间,事实上,你可以说它不应该。这会导致SIGSEGV或其他东西。但是,系统可以将相同的地址映射到不同的页面。这是Linux用.tbss / .tdata做的吗?在这种情况下,传递变量的地址将为您提供错误变量的地址!您将获得自己的本地副本,而不是您尝试传递的副本。或者,是否所有内容都共享并映射到不同的虚拟地址 - 允许您传递__thread vars的地址?

显然,应该通过传递其地址来尝试将线程本地存储传递到另一个线程来殴打和鞭打。还有一百万种其他方式 - 例如复制到任何其他变量!但是,如果有人知道,我很好奇。

  1. 这种情况下官方描述的行为
  2. 当前的GCC / Linux实施细节
  3. - 埃文

1 个答案:

答案 0 :(得分:5)

至少对于x86,使用段寄存器执行TLS。默认段寄存器%ds隐含在寻址存储器的指令中。访问TLS时,线程使用另一个段寄存器 - %gs用于i386,%fs用于x86-64 - 在调度线程时保存/恢复,就像其他寄存器在上下文切换中一样。

因此可以通过以下方式访问流程范围的变量:

mov (ADDR) -> REG ; load memory `myVar` to REG.

暗示:

mov %DS:(ADDR) -> REG

对于TLS,编译器生成:

mov %FS:(ADDR) -> REG ; load thread-local address `myVar` to REG.

实际上,即使变量的地址在不同的线程中看起来是相同的,例如,

fprintf(stdout, "%p\n", & myVar); /* in separate threads... */

事实上每个线程对段寄存器使用不同的值,这意味着它们映射到物理存储器的不同区域。如果您要将地址从一个线程传递到另一个线程,则无法访问它在第一个线程中表示的内存 - 另一个段寄存器值在第二个中生效em> thread。

Windows使用相同的方案(它可以交换%fs%gs - 不确定)和OS X的角色。对于其他架构,有一个深入的{{3 ELF ABI的TLS。它缺少对ARM体系结构的讨论,并且有关于IA-64和Alpha的详细信息,因此它显示了它的年龄。