Локальные переменные потока и сегмент fs
Я читаю из локальной переменной потока в моем коде вроде этого,
// tid_local is declared as __thread int tid_local;
long tid = tid_local
Оглядываясь на дизассемблированный код, я увидел что-то вроде этого, которое, как я подозреваю, является инструкцией, которая присваивает tid, читая tid_local.
movslq %fs:0xfffffffffffffffc,%rbx
Теперь мой вопрос в том, действительно ли это может быть инструкция, которая делает это, то есть чтение из локальной переменной потока, и если gcc всегда использует сегмент fs для хранения локальных переменных потока. Как это должно работать?
Ответы
Ответ 1
Да, это вполне может быть правильной инструкцией. Из руководства gcc
:
-mtls-direct-seg-refs
-mno-tls-direct-seg-refs
Управляет доступом к переменным TLS с смещениями из регистров сегмента TLS (% gs для 32-разрядных,% fs для 64-разрядных) или должен быть добавлен указатель на основе потока. Независимо от того, является ли это законным, зависит от операционной системы и отображает ли он сегмент для охвата всей области TLS.
edit Вот отличная ссылка, предложенная @janneb в комментариях: http://www.akkadia.org/drepper/tls.pdf
Ответ 2
Способ, которым различные потоки могут иметь разные сегменты fs, реализуется путем настройки локальных таблиц дескриптора (LDT) для каждого потока. Когда происходит переключение потоков, процессор автоматически загружает любые дескрипторы сегмента "нить-локальные" из соответствующей LDT. Вы можете проверить это, посмотрев на значение FS. Если бит 3 равен 1, то он использует LDT.
Ex. FS = 1B (который, как правило, является обычным селектором "CS" для Win NT) - это локальный поток.
Вы работаете так:
Селектор в двоичном формате
0000 0000 0001 1011
или
Индекс = 0000 0000 0001 [12 бит] (вторая запись в DT)
Таблица дескрипторов = 1 [1 бит] (1 == local, 0 == global)
RPL = 011 [3 бит] (запрошенный уровень привилегий = 3)