2012-10-14 27 views
9

Ulrich Drepper's paper在线程本地存储概述了TLS ABI几个不同的CPU架构,但我发现它不足以作为执行TLS的原因有两个基础:每个cpu arch真正的ELF TLS ABI要求是什么?

  1. 它省略了许多功能,如ARM重要archs ,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的要求吗?

+1

对不起,如果我问明显,但你检查了'GCC' TLS的支持?例如,'gcc-patches'邮件列表在今年6月1日开始有一个关于添加MIPS16 TLS支持的线程(http://marc.info/?l=gcc-patches&m=132586147826602)。与C库开发人员相比,编译器人员似乎对这类内容更为正式;他们可能会有更好的正式文件。 –

回答

3

我可以迄今收集到的最好的是:

对于任何一个TLS变种,__tls_get_addr或其他特定拱功能必须存在并有用于查找任何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片段。