C++ 如何在编译时获取thread_局部变量的偏移量

C++ 如何在编译时获取thread_局部变量的偏移量,c++,gcc,thread-local,C++,Gcc,Thread Local,在linux下使用gcc,我正在寻找一种方法来获取线程局部变量相对于线程局部存储区域的偏移量。 该偏移量包含在编译的对象文件中。 在我看来,应该有一个宏或内置的_,以获得它 运行时给出的代码如下所示。我需要的是在编译时得到那个常数 #include <iostream> #include <thread> thread_local int x; template<typename T> intptr_t getOffset(T& t){ r

在linux下使用gcc,我正在寻找一种方法来获取线程局部变量相对于线程局部存储区域的偏移量。 该偏移量包含在编译的对象文件中。 在我看来,应该有一个宏或内置的_,以获得它

运行时给出的代码如下所示。我需要的是在编译时得到那个常数

#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;
}
#包括
#包括
线程_局部int x;
模板
intptr\u getOffset(t&t){
return(intptr_t)&t-(intptr_t)pthread_self();
}
int main(int argc,字符**argv)
{       
标准::cout
在我看来,应该有一个宏或内置的_,以获得它

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

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

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

您可以建议Binutils开发人员考虑添加一个链接时间重定位来计算可执行文件中的THeLead本地偏移量,甚至在运行时重新定位,以计算TraceLead在一般情况下的本地值,但是它们将需要强制性的用例来考虑这样的建议。 作为穷人的变通方法,您可以编译代码两次,并从symtab中提取偏移量:

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

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