Jaké je tedy použití GS?
x86_64 Linuxové jádro používá registr GS jako efektivní způsob získání zásobníku prostoru jádra pro systémová volání.
Registr GS ukládá základní adresu pro oblast na procesor. Chcete-li získat zásobník prostoru jádra, v entry_SYSCALL_64
movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp
Po rozbalení PER_CPU_VAR dostaneme následující:
movq %gs:cpu_current_top_of_stack, %rsp
Chcete-li skutečně odpovědět na váš fs:0 otázka:x86_64 ABI vyžaduje fs:0 obsahuje adresu, na kterou ukazuje fs sám. To znamená fs:-4 načte hodnotu uloženou v fs:0 - 4 . Tato funkce je nezbytná, protože nemůžete snadno získat adresu, na kterou ukazuje fs bez procházení kódu jádra. S adresou uloženou na fs:0 díky tomu je práce s místním úložištěm vláken mnohem efektivnější.
Můžete to vidět v akci, když vezmete adresu lokální proměnné vlákna:
static __thread int test = 0;
int *f(void) {
return &test;
}
int g(void) {
return test;
}
zkompiluje do
f:
movq %fs:0, %rax
leaq -4(%rax), %rax
retq
g:
movl %fs:-4, %eax
retq
i686 dělá totéž, ale s %gs . Na aarch64 to není nutné, protože adresu lze číst ze samotného registru tls.
V x86-64 jsou 3 záznamy TLS, dva z nich jsou přístupné přes FS a GS, FS používá interně glibc (v IA32 zřejmě FS používá Wine a GS glibc).
Glibc vytvoří svůj vstupní bod TLS na struct pthread který obsahuje některé vnitřní struktury pro závitování. Glibc obvykle odkazuje na struct pthread proměnná jako pd , pravděpodobně pro deskriptor pthread .
Na x86-64, struct pthread začíná tcbhead_t (to záleží na architektuře, viz makra TLS_DTV_AT_TP a TLS_TCB_AT_TP ). Toto záhlaví řídicího bloku vlákna, AFAIU, obsahuje některá pole, která jsou potřebná, i když existuje jediné vlákno. DTV je vektor dynamického vlákna a obsahuje ukazatele na bloky TLS pro DSO načtené přes dlopen() . Před nebo za TCB je statický blok TLS pro spustitelný soubor a DSO spojené v době načítání (programu). TCB a DTV jsou docela dobře vysvětleny v dokumentu TLS Ulricha Dreppera (viz diagramy v kapitole 3).