【问题标题】:How to get at compile time the offset of a thread_local variable如何在编译时获取 thread_local 变量的偏移量
【发布时间】:2016-08-24 12:51:02
【问题描述】:

在linux下使用gcc,我正在寻找一种方法来获取线程本地变量相对于线程本地存储区域的偏移量。 该偏移量包含在编译的目标文件中。 在我看来,应该有一个宏或 built_in 来获取它。

在运行时给出的代码如下代码所示。我需要的是在编译时获得该常量。

#include <iostream>
#include <thread>

thread_local int x;

template<typename T>
intptr_t getOffset(T& t){
    return (intptr_t)&t-(intptr_t)pthread_self();
}

int main(int argc, char **argv)
{       
    std::cout<<"offset:"<<getOffset<int>(x)<<std::endl;
}

【问题讨论】:

  • 根据the ELF thread-local storage spec,偏移量直到运行时才确定,因为它取决于模块加载的顺序和特定于体系结构的 TCB 的大小(在编译时不知道,因为你可以在不同版本的操作系统上运行二进制文件,每个版本都有不同的 TCB)。
  • @RaymondChen 通过添加一些乘法指令后编译的文件的 objdump ,我从转储中清楚地看到在编译代码中指定了偏移量(在这种情况下是 -4 )。因此,在特定情况下,它在编译时是已知的。因此,在这种情况下,二进制文件只有一个解释 40153d: 64 8b 14 25 fc ff ff mov %fs:0xfffffffffffffffc,%edx 401544: ff 401545: 64 8b 04 25 fc ff ff mov %fs:0xffffffffffffffc,%eax 40154c:
  • @RaymondChen 我怀疑他在某些情况下可能能够依赖这个偏移量(见我的回答)。不过,这并不能证明对编译器的完全支持是合理的。

标签: c++ gcc thread-local


【解决方案1】:

在我看来,应该有一个宏或内置函数来获取它。

这样的宏实现起来并不容易/便宜。首先,您只能在编译可执行文件时确定这样的偏移量,因为对于动态库,它将取决于库在加载它的可执行文件的依赖列表中的相对位置(如果库是通过 dlopen 动态加载的,甚至不在静态 TLS 块中) ,因此无法通过 TCB 的恒定偏移量访问)。

现在,即使您尝试确定可执行文件中的偏移量,也只能针对可执行文件本身中的 thread_local 变量执行此操作,因为库的 thread_local 段的大小(及其偏移量)仅在程序启动时确定(这可能是因为加载库的版本可能比可执行文件链接的版本更新,因此thread_local 段大小也可能不同。

最后,即使对于可执行文件的变量,它也将取决于链接期间目标文件和静态/动态库的相对顺序,因此您需要静态链接器中的特殊支持来计算偏移量。

您可能会建议 Binutils 开发人员考虑添加链接时重定位以计算可执行文件中的 thread_local 偏移量,或者在一般情况下甚至是运行时重定位以计算 thread_local,但他们将需要令人信服的用例来考虑此类提议。

作为穷人的解决方法,您可以编译您的代码两次并从 symtab 中提取偏移量:

$ readelf -sW tmp.o | awk '/TLS/{print $8 " " $2}'
yyy 0000000000000000
xxx 0000000000000004

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-27
    • 2014-09-14
    • 1970-01-01
    • 2017-03-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多