首页 文章

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

提问于
浏览
9

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

  • 它省略了许多重要的拱门,如ARM,MIPS等(虽然包括一堆与Itanium完全无关的)

  • 更重要的是,它将大量实现细节与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要求?

1 回答

  • 3

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

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

    对于TLS变体II(i386等),"thread pointer register"(可能实际上不是一个寄存器,但可能是某种机制,如 %gs:0 或者甚至是内核空间的陷阱;为了简单起见,我们只是将其称为寄存器)指向结束主要可执行文件的TLS段,其中"just past the end"包括舍入到TLS段对齐的下一个倍数 .

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

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

相关问题