2012-10-14 25 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片段。