|
| 1 | +.. SPDX-License-Identifier: GPL-2.0 |
| 2 | +
|
| 3 | +Using FS and GS segments in user space applications |
| 4 | +=================================================== |
| 5 | + |
| 6 | +The x86 architecture supports segmentation. Instructions which access |
| 7 | +memory can use segment register based addressing mode. The following |
| 8 | +notation is used to address a byte within a segment: |
| 9 | + |
| 10 | + Segment-register:Byte-address |
| 11 | + |
| 12 | +The segment base address is added to the Byte-address to compute the |
| 13 | +resulting virtual address which is accessed. This allows to access multiple |
| 14 | +instances of data with the identical Byte-address, i.e. the same code. The |
| 15 | +selection of a particular instance is purely based on the base-address in |
| 16 | +the segment register. |
| 17 | + |
| 18 | +In 32-bit mode the CPU provides 6 segments, which also support segment |
| 19 | +limits. The limits can be used to enforce address space protections. |
| 20 | + |
| 21 | +In 64-bit mode the CS/SS/DS/ES segments are ignored and the base address is |
| 22 | +always 0 to provide a full 64bit address space. The FS and GS segments are |
| 23 | +still functional in 64-bit mode. |
| 24 | + |
| 25 | +Common FS and GS usage |
| 26 | +------------------------------ |
| 27 | + |
| 28 | +The FS segment is commonly used to address Thread Local Storage (TLS). FS |
| 29 | +is usually managed by runtime code or a threading library. Variables |
| 30 | +declared with the '__thread' storage class specifier are instantiated per |
| 31 | +thread and the compiler emits the FS: address prefix for accesses to these |
| 32 | +variables. Each thread has its own FS base address so common code can be |
| 33 | +used without complex address offset calculations to access the per thread |
| 34 | +instances. Applications should not use FS for other purposes when they use |
| 35 | +runtimes or threading libraries which manage the per thread FS. |
| 36 | + |
| 37 | +The GS segment has no common use and can be used freely by |
| 38 | +applications. GCC and Clang support GS based addressing via address space |
| 39 | +identifiers. |
| 40 | + |
| 41 | +Reading and writing the FS/GS base address |
| 42 | +------------------------------------------ |
| 43 | + |
| 44 | +There exist two mechanisms to read and write the FS/GS base address: |
| 45 | + |
| 46 | + - the arch_prctl() system call |
| 47 | + |
| 48 | + - the FSGSBASE instruction family |
| 49 | + |
| 50 | +Accessing FS/GS base with arch_prctl() |
| 51 | +-------------------------------------- |
| 52 | + |
| 53 | + The arch_prctl(2) based mechanism is available on all 64-bit CPUs and all |
| 54 | + kernel versions. |
| 55 | + |
| 56 | + Reading the base: |
| 57 | + |
| 58 | + arch_prctl(ARCH_GET_FS, &fsbase); |
| 59 | + arch_prctl(ARCH_GET_GS, &gsbase); |
| 60 | + |
| 61 | + Writing the base: |
| 62 | + |
| 63 | + arch_prctl(ARCH_SET_FS, fsbase); |
| 64 | + arch_prctl(ARCH_SET_GS, gsbase); |
| 65 | + |
| 66 | + The ARCH_SET_GS prctl may be disabled depending on kernel configuration |
| 67 | + and security settings. |
| 68 | + |
| 69 | +Accessing FS/GS base with the FSGSBASE instructions |
| 70 | +--------------------------------------------------- |
| 71 | + |
| 72 | + With the Ivy Bridge CPU generation Intel introduced a new set of |
| 73 | + instructions to access the FS and GS base registers directly from user |
| 74 | + space. These instructions are also supported on AMD Family 17H CPUs. The |
| 75 | + following instructions are available: |
| 76 | + |
| 77 | + =============== =========================== |
| 78 | + RDFSBASE %reg Read the FS base register |
| 79 | + RDGSBASE %reg Read the GS base register |
| 80 | + WRFSBASE %reg Write the FS base register |
| 81 | + WRGSBASE %reg Write the GS base register |
| 82 | + =============== =========================== |
| 83 | + |
| 84 | + The instructions avoid the overhead of the arch_prctl() syscall and allow |
| 85 | + more flexible usage of the FS/GS addressing modes in user space |
| 86 | + applications. This does not prevent conflicts between threading libraries |
| 87 | + and runtimes which utilize FS and applications which want to use it for |
| 88 | + their own purpose. |
| 89 | + |
| 90 | +FSGSBASE instructions enablement |
| 91 | +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| 92 | + The instructions are enumerated in CPUID leaf 7, bit 0 of EBX. If |
| 93 | + available /proc/cpuinfo shows 'fsgsbase' in the flag entry of the CPUs. |
| 94 | + |
| 95 | + The availability of the instructions does not enable them |
| 96 | + automatically. The kernel has to enable them explicitly in CR4. The |
| 97 | + reason for this is that older kernels make assumptions about the values in |
| 98 | + the GS register and enforce them when GS base is set via |
| 99 | + arch_prctl(). Allowing user space to write arbitrary values to GS base |
| 100 | + would violate these assumptions and cause malfunction. |
| 101 | + |
| 102 | + On kernels which do not enable FSGSBASE the execution of the FSGSBASE |
| 103 | + instructions will fault with a #UD exception. |
| 104 | + |
| 105 | + The kernel provides reliable information about the enabled state in the |
| 106 | + ELF AUX vector. If the HWCAP2_FSGSBASE bit is set in the AUX vector, the |
| 107 | + kernel has FSGSBASE instructions enabled and applications can use them. |
| 108 | + The following code example shows how this detection works:: |
| 109 | + |
| 110 | + #include <sys/auxv.h> |
| 111 | + #include <elf.h> |
| 112 | + |
| 113 | + /* Will be eventually in asm/hwcap.h */ |
| 114 | + #ifndef HWCAP2_FSGSBASE |
| 115 | + #define HWCAP2_FSGSBASE (1 << 1) |
| 116 | + #endif |
| 117 | + |
| 118 | + .... |
| 119 | + |
| 120 | + unsigned val = getauxval(AT_HWCAP2); |
| 121 | + |
| 122 | + if (val & HWCAP2_FSGSBASE) |
| 123 | + printf("FSGSBASE enabled\n"); |
| 124 | + |
| 125 | +FSGSBASE instructions compiler support |
| 126 | +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| 127 | + |
| 128 | +GCC version 4.6.4 and newer provide instrinsics for the FSGSBASE |
| 129 | +instructions. Clang 5 supports them as well. |
| 130 | + |
| 131 | + =================== =========================== |
| 132 | + _readfsbase_u64() Read the FS base register |
| 133 | + _readfsbase_u64() Read the GS base register |
| 134 | + _writefsbase_u64() Write the FS base register |
| 135 | + _writegsbase_u64() Write the GS base register |
| 136 | + =================== =========================== |
| 137 | + |
| 138 | +To utilize these instrinsics <immintrin.h> must be included in the source |
| 139 | +code and the compiler option -mfsgsbase has to be added. |
| 140 | + |
| 141 | +Compiler support for FS/GS based addressing |
| 142 | +------------------------------------------- |
| 143 | + |
| 144 | +GCC version 6 and newer provide support for FS/GS based addressing via |
| 145 | +Named Address Spaces. GCC implements the following address space |
| 146 | +identifiers for x86: |
| 147 | + |
| 148 | + ========= ==================================== |
| 149 | + __seg_fs Variable is addressed relative to FS |
| 150 | + __seg_gs Variable is addressed relative to GS |
| 151 | + ========= ==================================== |
| 152 | + |
| 153 | +The preprocessor symbols __SEG_FS and __SEG_GS are defined when these |
| 154 | +address spaces are supported. Code which implements fallback modes should |
| 155 | +check whether these symbols are defined. Usage example:: |
| 156 | + |
| 157 | + #ifdef __SEG_GS |
| 158 | + |
| 159 | + long data0 = 0; |
| 160 | + long data1 = 1; |
| 161 | + |
| 162 | + long __seg_gs *ptr; |
| 163 | + |
| 164 | + /* Check whether FSGSBASE is enabled by the kernel (HWCAP2_FSGSBASE) */ |
| 165 | + .... |
| 166 | + |
| 167 | + /* Set GS base to point to data0 */ |
| 168 | + _writegsbase_u64(&data0); |
| 169 | + |
| 170 | + /* Access offset 0 of GS */ |
| 171 | + ptr = 0; |
| 172 | + printf("data0 = %ld\n", *ptr); |
| 173 | + |
| 174 | + /* Set GS base to point to data1 */ |
| 175 | + _writegsbase_u64(&data1); |
| 176 | + /* ptr still addresses offset 0! */ |
| 177 | + printf("data1 = %ld\n", *ptr); |
| 178 | + |
| 179 | + |
| 180 | +Clang does not provide the GCC address space identifiers, but it provides |
| 181 | +address spaces via an attribute based mechanism in Clang 2.6 and newer |
| 182 | +versions: |
| 183 | + |
| 184 | + ==================================== ===================================== |
| 185 | + __attribute__((address_space(256)) Variable is addressed relative to GS |
| 186 | + __attribute__((address_space(257)) Variable is addressed relative to FS |
| 187 | + ==================================== ===================================== |
| 188 | + |
| 189 | +FS/GS based addressing with inline assembly |
| 190 | +------------------------------------------- |
| 191 | + |
| 192 | +In case the compiler does not support address spaces, inline assembly can |
| 193 | +be used for FS/GS based addressing mode:: |
| 194 | + |
| 195 | + mov %fs:offset, %reg |
| 196 | + mov %gs:offset, %reg |
| 197 | + |
| 198 | + mov %reg, %fs:offset |
| 199 | + mov %reg, %gs:offset |
0 commit comments