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

时间:2012-10-14 02:03:04

标签: c linux elf abi thread-local-storage

线程本地存储上的

Ulrich Drepper's paper概述了几种不同cpu架构的TLS ABI,但我发现它不足以作为实现TLS的基础,原因有两个:

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

1 个答案:

答案 0 :(得分:3)

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

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

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

对于TLS变体I,“线程指针寄存器”指向主要可执行文件的TLS段的开头的某个固定偏移量。这种偏移因拱而异。 (已经在一些丑陋的RISC拱门上选择了最大化通过带符号的16位偏移可访问的TLS数量,这让我觉得非常无用,因为编译器无法知道重定位偏移是否适合16位因此必须总是使用load-upper / add指令生成更慢,更大的32位偏移代码。

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