В Linux TLS настраивается ядром или libc (или другой языковой средой выполнения)?

Я просто изучаю, как TLS (локальное хранилище потоков) реализовано в системах Linux. В документе Обработка ELF для локального хранилища потока объясняется, как требования программы к локальным переменным потока могут быть закодированы в двоичном формате ELF, и как «среда выполнения» должна обрабатывать такие двоичные файлы.

Однако мне не ясно, будет ли на практике «среда выполнения», которая устанавливает область (области) TLS, ядро ​​​​Linux (и его код для загрузки двоичных файлов ELF) или какой-либо код инициализации в libc. Кто-нибудь может кратко объяснить?

(Предыстория: я пытаюсь статически связать и запустить приложение, но при запуске оно выдает ошибку сегментации. В gdb я вижу, что код ошибки сегментации — это какой-то код инициализации из libc. Он пытается прочитать статическую переменную с помощью адрес относительно GS, но GS равен нулю.)


person Alex D    schedule 21.05.2015    source источник
comment
glibc и musl имеют открытый исходный код; вы можете проверить их исходный код.   -  person Colonel Thirty Two    schedule 21.05.2015
comment
Вы обсуждаете TLS (локальное хранилище потока) или TLS (безопасность транспортного уровня)? Содержимое предполагает локальное хранилище потока; тег ssl предполагает последнее. Вы были синонимами? Я удалил ssl и добавил thread-local-storage, хотя tls само собой не сопоставляется с ssl.   -  person Jonathan Leffler    schedule 21.05.2015
comment
@JonathanLeffler, я добавил tls, что означает локальное хранилище потока. Спасибо за исправление ошибки.   -  person Alex D    schedule 21.05.2015
comment
я проверил; tls является синонимом ssl .   -  person Jonathan Leffler    schedule 22.05.2015


Ответы (1)


Инициализация локального хранилища потока является частью кода запуска, предоставляемого libc. При статической компоновке ваш компоновщик должен добавить инициализацию TLS в стартовый код, связанный с вашей программой.

Например, glibc имеет __libc_setup_tls и _dl_tls_setup (среди прочего, связанные вещи) в libc.a, которые будут добавлены к коду инициализации вашей программы, если вы линкуете, скажем, через gcc -static. (Для динамически скомпонованных программ функции _dl_... являются частью динамического компоновщика-загрузчика ELF, ld-linux.so, который не используется для запуска статически скомпонованных программ.)

Таким образом, правильная инициализация TLS в статически связанном исполняемом файле является результатом совместной работы вашей библиотеки C (которая предоставляет код) и вашей цепочки инструментов (которая должна понимать, как правильно связать весь необходимый стартовый код).

Участие ядра в инициализации TLS незначительно. (По сути, нужно просто убедиться, что раздел .tdata доступен для libc для инициализации.) См. разделы TLS файла ELF и программы LOAD для получения подробной информации.

person user3113526    schedule 27.05.2015
comment
Это не дает ответа на ключевой вопрос о том, как сегмент GS настраивается для указания раздела TLS. Это то, что может сделать только ядро. - person Ross Ridge; 28.05.2015
comment
Я еще не смотрел glibc, но только что проверил musl. Он инициализирует TLS при запуске (как вы сказали), но затем также использует системный вызов set_thread_area для создания записи в LDT процесса, которая указывает на пространство, выделенное для TLS. Затем libc устанавливает регистр %gs так, чтобы он ссылался на запись LDT для TLS. (Это на x86-32 - x86-64 использует другой сегментный регистр.) - person Alex D; 28.05.2015