在Linux系统中,TLS是由内核还是libc(或其他语言运行时)设置的?

8
我正在学习TLS(线程本地存储)在Linux系统上的实现。 ELF Handling for Thread-Local Storage文档解释了如何将程序对线程本地变量的需求编码到ELF二进制文件中,以及“运行时”应该如何处理这些二进制文件。
然而,我不确定在实践中设置TLS区域的“运行时”是Linux内核(及其用于加载ELF二进制文件的代码)还是libc中的一些初始化代码。 有人能简要解释一下吗?
(背景:我正在尝试静态链接并运行一个应用程序,但它在启动时会出现段错误。 在gdb中,我可以看到libc的一些初始化代码正在导致段错误。 它正在尝试使用相对于GS的地址读取静态变量,但GS为零。)

2
glibc和musl是开源的,你可以查看它们的源代码。 - Colonel Thirty Two
3
您是在讨论线程本地存储(TLS)还是传输层安全协议(TLS)?内容表明您正在讨论线程本地存储,但标签[标签:ssl]表明后者。是否已进行了同义词处理?我已经移除了[标签:ssl]并添加了[标签:thread-local-storage],虽然[标签:tls]并没有明显地被映射到[标签:ssl]。 - Jonathan Leffler
@JonathanLeffler,我添加了tls,意思是线程本地存储。感谢您纠正错误。 - Alex D
我已经查过了,[tag:tls]是[tag:ssl]的同义词。 - Jonathan Leffler
1个回答

5

线程局部存储初始化是由libc提供的启动代码的一部分。在静态链接时,您的链接器应该将TLS初始化添加到链接到您的程序中的启动代码中。

例如,glibc在libc.a中具有__libc_setup_tls_dl_tls_setup(以及其他相关内容),如果您通过gcc-static进行链接,则会将它们添加到程序的初始化代码中。(对于动态链接程序,_dl_...函数是ELF动态链接器加载器ld-linux.so的一部分,该加载器不用于运行静态链接程序。)

因此,在静态链接可执行文件中进行适当的TLS初始化是您的C库(提供代码)和工具链(必须了解如何正确地链接所有必要的启动代码)之间协作的结果。

内核在TLS初始化中的参与非常小。(基本上,它只需要确保.tdata节可供libc进行初始化。)有关详细信息,请参见 ELF文件TLS和LOAD程序段


这并没有回答关键问题,即如何设置GS段以指向TLS部分。这只有内核才能做到。 - Ross Ridge
我还没有看过glibc, 但我刚刚查了一下musl. 它在启动时初始化TLS(就像你说的那样),然后还使用set_thread_area系统调用,在进程的LDT中创建一个条目,该条目指向为TLS分配的空间。然后libc设置%gs寄存器,使其指向TLS的LDT条目。(这是对于x86-32来说的,x86-64使用不同的段寄存器。) - Alex D

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接