On the x86-64 architecture, two registers have a special purpose: FS and GS. In linux 2.6.*, the FS register seem to be used to store thread-local information.
- Is that correct?
- What is stored at fs:0? Is there any C structure that describe this content?
- What is then the use of GS?
In x86-64 there are 3 TLS entries, two of them accesible via FS and GS, FS is used internally by glibc (in IA32 apparently FS is used by Wine and GS by glibc).
Glibc makes its TLS entry point to a
struct pthread
that contains some internal structures for threading. Glibc usually refers to astruct pthread
variable aspd
, presumably for pthread descriptor.On x86-64,
struct pthread
starts with atcbhead_t
(this depends on the architecture, see the macrosTLS_DTV_AT_TP
andTLS_TCB_AT_TP
). This Thread Control Block Header, AFAIU, contains some fields that are needed even when there is a single thread. The DTV is the Dynamic Thread Vector, and contains pointers to TLS blocks for DSOs loaded viadlopen()
. Before or after the TCB there is a static TLS block for the executable and DSOs linked at (program's) load time. The TCB and DTV are explained pretty well in Ulrich Drepper's TLS document (look for the diagrams in chapter 3).What is then the use of GS?
x86_64 Linux kernel uses GS register as a efficiency way to acquire kernel space stack for system calls.
GS register stores the base address for per-cpu area. To acquire the kernel space stack, in entry_SYSCALL_64
After expanding PER_CPU_VAR, we get the following:
To actually answer your
fs:0
question: The x86_64 ABI requires thatfs:0
contains the address "pointed to" byfs
itself. That is,fs:-4
loads the value stored atfs:0 - 4
. This feature is necessary because you cannot easily get the address pointed to byfs
without going through kernel code. Having the address stored atfs:0
thus makes working with thread local storage much more efficient.You can see this in action when you take the address of a thread local variable:
compiles to
i686 does the same but with
%gs
. On aarch64 this is not necessary because the address can be read from the tls register itself.