Ulrich Drepper's paper概述了几种不同cpu架构的TLS ABI,但我发现它不足以作为实现TLS的基础,原因有两个:
例如,i386唯一的实际ABI要求是:
%gs:0
指向指向自身的指针。___tls_get_addr
和__tls_get_addr
函数必须存在正确的语义才能查找任意TLS段。特别是,DTV的存在或布局是不 ABI的一部分,也不是主程序以外的TLS段的排序/布局。
似乎任何使用“TLS变体II”的拱门都具有大致上述ABI要求。但我完全不理解“TLS变体I”的要求,而且从阅读资料(在uClibc和glibc中)看来,甚至可能存在“变体I”的几种变体。
我应该查看哪些更好的文件,或者熟悉TLS工作的人是否可以向我解释ABI要求?
答案 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段。