A cosa serve allora GS?
x86_64 Il kernel Linux utilizza il registro GS come un modo efficiente per acquisire lo stack dello spazio del kernel per le chiamate di sistema.
Il registro GS memorizza l'indirizzo di base per l'area per CPU. Per acquisire lo stack dello spazio del kernel, in entry_SYSCALL_64
movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp
Dopo aver espanso PER_CPU_VAR, otteniamo quanto segue:
movq %gs:cpu_current_top_of_stack, %rsp
Per rispondere effettivamente al tuo fs:0
domanda:l'ABI x86_64 richiede che fs:0
contiene l'indirizzo "indicato" da fs
si. Ovvero, fs:-4
carica il valore memorizzato in fs:0 - 4
. Questa funzione è necessaria perché non è possibile ottenere facilmente l'indirizzo indicato da fs
senza passare attraverso il codice del kernel. Avere l'indirizzo memorizzato in fs:0
quindi rende il lavoro con l'archiviazione locale dei thread molto più efficiente.
Puoi vederlo in azione quando prendi l'indirizzo di una variabile locale del thread:
static __thread int test = 0;
int *f(void) {
return &test;
}
int g(void) {
return test;
}
compila in
f:
movq %fs:0, %rax
leaq -4(%rax), %rax
retq
g:
movl %fs:-4, %eax
retq
i686 fa lo stesso ma con %gs
. Su aarch64 questo non è necessario perché l'indirizzo può essere letto dal registro tls stesso.
In x86-64 ci sono 3 voci TLS, due delle quali accessibili tramite FS e GS, FS è usato internamente da glibc (in IA32 apparentemente FS è usato da Wine e GS da glibc).
Glibc imposta il suo punto di ingresso TLS su un struct pthread
che contiene alcune strutture interne per la filettatura. Glibc di solito si riferisce a un struct pthread
variabile come pd
, presumibilmente per pthread descriptor .
Su x86-64, struct pthread
inizia con un tcbhead_t
(questo dipende dall'architettura, vedi le macro TLS_DTV_AT_TP
e TLS_TCB_AT_TP
). Questa intestazione del blocco di controllo del thread, AFAIU, contiene alcuni campi necessari anche quando è presente un singolo thread. Il DTV è il Dynamic Thread Vector e contiene puntatori a blocchi TLS per DSO caricati tramite dlopen()
. Prima o dopo il TCB c'è un blocco TLS statico per l'eseguibile e i DSO collegati al momento del caricamento (del programma). Il TCB e il DTV sono spiegati abbastanza bene nel documento TLS di Ulrich Drepper (cerca i diagrammi nel capitolo 3).