Каковы реальные требования ELF TLS ABI для каждой арки процессора?
бумага Ульриха Дреппера в потоковом локальном хранилище описывается TLS ABI для нескольких разных архитектур ЦП, но я нахожу его недостаточным в качестве основы для реализации TLS по двум причинам:
- он опускает ряд важных дуг, таких как ARM, MIPS и т. д. (в то время как включая кучу совершенно неуместных, таких как Itanium)
- что еще более важно, он смешивает много деталей реализации с ABI, так что трудно сказать, какие свойства необходимы для взаимодействия, и которые являются аспектами его реализации.
в качестве примера, единственными фактическими требованиями ABI для i386 являются:
-
%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 ответов
лучшее, что я могу собрать до сих пор:
для любого варианта TLS,__tls_get_addr
или другие функции, специфичные для arch, должны существовать и иметь правильную семантику для поиска любого объекта TLS, а относительное смещение между любыми двумя сегментами TLS должно быть константой времени выполнения (одинаковое смещение для каждого потока).
для варианта II TLS (i386 и т. д.), "регистр указателя потока" (который на самом деле не может быть регистром, но, возможно, какой-то механизм, такой как %gs:0
или даже ловушки, в kernelspace; для простоты, хотя давайте просто назовем его регистром) points сразу после конца сегмента TLS для основного исполняемого файла, где "сразу после окончания" включает округление до следующего кратного выравнивания сегмента TLS.
для варианта TLS I "регистр указателя потока" указывает на некоторое фиксированное смещение от начало сегмента TLS для основного исполняемого файла. Это смещение зависит от арки. (Он был выбран на некоторых уродливых арках RISC, чтобы максимизируйте количество TLS, доступных через подписанные 16-битные смещения, что кажется мне чрезвычайно бесполезным, поскольку компилятор не может знать, будет ли перемещенное смещение соответствовать 16 битам и, следовательно, всегда должен генерировать более медленный, больший 32-битный код смещения, используя инструкции load-upper/add).
насколько я могу судить, ничего о TCBs, DTVs и т. д. является частью ABI в том смысле, что приложениям не разрешен доступ к этим структурам, а также расположение любого TLS сегмент, отличный от основной исполняемой части ABI. В обоих вариантах I и II имеет смысл хранить реализацию-внутреннюю информацию для потока с фиксированным смещением от "регистра указателя потока", в любом случае безопасно избегая перекрытия сегмента TLS.