Как регистры fs/gs используются в Linux AMD64?
В архитектуре x86-64 два регистра имеют особое назначение: FS и GS. В linux 2.6. * Регистр FS используется для хранения информации о локальных потоках.
- Правильно ли это?
- Что хранится в fs: 0? Существует ли структура C, описывающая этот контент?
- Что такое использование GS?
Ответы
Ответ 1
В x86-64 есть 3 записи TLS, два из них доступны через FS и GS, FS используется внутренне с помощью glibc (в IA32, по-видимому, FS используется Wine и GS glibc).
Glibc делает точку входа TLS в struct pthread
, которая содержит некоторые внутренние структуры для потоковой передачи. Glibc обычно ссылается на переменную struct pthread
как pd
, предположительно для дескриптора pthread.
На x86-64, struct pthread
начинается с tcbhead_t
(это зависит от архитектуры, см. макросы TLS_DTV_AT_TP
и TLS_TCB_AT_TP
). Этот заголовок блока управления заголовком, AFAIU, содержит некоторые поля, которые необходимы, даже если есть один поток. DTV является динамическим вектором потока и содержит указатели на блоки TLS для DSO, загружаемых через dlopen()
. До или после TCB существует статический TLS-блок для исполняемого файла и DSO, связанный с временем загрузки (программы). TCB и DTV хорошо объясняются в документе Ulrich Drepper TLS (ищите диаграммы в главе 3).
Ответ 2
Чтобы ответить на ваш вопрос fs:0
: для AB86 x86_64 требуется, чтобы fs:0
содержал адрес "указал" на fs
. То есть fs:-4
загружает значение, сохраненное в fs:0 - 4
. Эта функция необходима, потому что вы не можете легко получить адрес, на который указывает fs
, без прохождения кода ядра. Наличие адреса, сохраненного в fs:0
, тем самым делает работу с локальным хранилищем потоков намного более эффективной.
Это можно увидеть в действии, когда вы берете адрес локальной переменной потока:
static __thread int test = 0;
int *f(void) {
return &test;
}
int g(void) {
return test;
}
компилируется в
f:
movq %fs:0, %rax
leaq -4(%rax), %rax
retq
g:
movl %fs:-4, %eax
retq
i686 делает то же самое, но с %gs
. На aarch64 это не обязательно, потому что адрес может быть прочитан из самого регистра tls.