每个cpu arch的真正ELF TLS ABI要求是什么?

R..*_*R.. 9 c linux elf abi thread-local-storage

Ulrich Drepper关于线程本地存储的论文概述了几种不同cpu架构的TLS ABI,但我发现它不足以作为实现TLS的基础,原因有两个:

  1. 它省略了许多重要的拱门,如ARM,MIPS等(虽然包括一堆与Itanium完全无关的)
  2. 更重要的是,它将大量实现细节与ABI混合在一起,因此很难说出互操作性需要哪些属性,哪些只是其实现的一部分.

例如,i386唯一的实际ABI要求是:

  • %gs:0 指向指向自身的指针.
  • 主可执行文件的TLS段(如果有)必须位于此地址的固定(通过链接器,负)偏移量.
  • 初始加载的库的所有其他TLS段必须具有相对于此地址的运行时常量(即,对于每个线程相同,但在不同的程序运行中不一定相同)(并且动态链接器必须能够填充重定位)这些补偿).
  • ___tls_get_addr并且__tls_get_addr函数必须以正确的语义存在,以便查找任意TLS段.

特别是,DTV的存在或布局不是 ABI的一部分,也不是主程序之外的TLS段的排序/布局.

似乎任何使用"TLS变体II"的拱门都具有大致上述ABI要求.但我完全不了解"TLS变体I"的要求,而且从阅读来源(在uClibc和glibc中)看来,甚至可能存在"变体I"的几种变体.

有没有更好的文件我应该看一下,或者熟悉TLS工作的人能向我解释ABI的要求吗?

R..*_*R.. 3

到目前为止我能收集到的最好的信息是:

对于任一 TLS 变体,__tls_get_addr或其他特定于架构的函数,必须存在并且具有用于查找任何 TLS 对象的正确语义,并且任何两个 TLS 段之间的相对偏移量必须是运行时常量(每个线程的偏移量相同)。

对于 TLS 变体 II(i386 等),“线程指针寄存器”(实际上可能不是寄存器,但可能是某种机制%gs:0,甚至是内核空间的陷阱;为简单起见,我们将其称为寄存器)指向仅指向超过主可执行文件的 TLS 段的末尾,其中“刚刚超过末尾”包括向上舍入到 TLS 段对齐的下一个倍数。

对于 TLS 变体 I,“线程指针寄存器”指向距主可执行文件的 TLS 段开头的某个固定偏移量。该偏移量因牙弓而异。(在一些丑陋的 RISC 架构上选择它是为了最大化通过签名 16 位偏移量访问的 TLS 数量,这让我觉得非常无用,因为编译器无法知道重定位的偏移量是否适合 16 位,因此必须始终使用加载上部/添加指令生成较慢、较大的 32 位偏移代码)。

据我所知,关于 TCB、DTV 等的任何内容都不是 ABI 的一部分,因为不允许应用程序访问这些结构,除了主可执行文件部分之外的任何 TLS 段的位置也不是 ABI 的一部分。 ABI。在变体 I 和 II 中,将线程的实现内部信息存储在距“线程指针寄存器”的固定偏移处是有意义的,无论哪种方式都可以安全地避免重叠 TLS 段。