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

On Linux, is TLS set up by the kernel or by libc (or other language runtime)?

我正在研究如何在 Linux 系统上实现 TLS(线程本地存储)。文档 ELF Handling for Thread-Local Storage 解释了如何将程序对线程局部变量的要求编码为 ELF 二进制文件,以及 "runtime" 应如何处理此类二进制文件。

但是,我不清楚实际上设置 TLS 区域的 "runtime" 是 Linux 内核(及其加载 ELF 二进制文件的代码)还是某些libc 中的初始化代码。有人可以简单解释一下吗?

(背景:我正在尝试静态地-link 和 运行 一个应用程序,但它在启动时出现段错误。在 gdb 中,我可以看到段错误代码是来自 libc 的一些初始化代码。它试图使用相对于 GS 的地址读取静态变量,但 GS 为零。)

线程本地存储初始化是 libc 提供的启动代码的一部分。当静态 linking 时,您的 linker 应该将 TLS 初始化添加到启动代码 linked 到您的程序中。

例如,glibc 在 libc.a 中有 __libc_setup_tls_dl_tls_setup(以及其他相关内容),如果您 link 通过,比方说,gcc -static。 (对于动态 linked 程序,_dl_... 函数是 ELF 动态 linker-loader ld-linux.so 的一部分,它不用于 运行 静态 linked 程序。)

因此,静态 linked 可执行文件中正确的 TLS 初始化是 C 库(提供代码)和工具链(必须了解如何正确 link 在所有必要的启动代码中)。

内核对 TLS 初始化的参与很小。 (基本上,它只需要确保 .tdata 部分可用于 libc 进行初始化。)有关详细信息,请参阅 ELF file TLS and LOAD program sections