mirror of https://github.com/Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
199 lines
7.0 KiB
199 lines
7.0 KiB
.. SPDX-License-Identifier: GPL-2.0 |
|
|
|
Using FS and GS segments in user space applications |
|
=================================================== |
|
|
|
The x86 architecture supports segmentation. Instructions which access |
|
memory can use segment register based addressing mode. The following |
|
notation is used to address a byte within a segment: |
|
|
|
Segment-register:Byte-address |
|
|
|
The segment base address is added to the Byte-address to compute the |
|
resulting virtual address which is accessed. This allows to access multiple |
|
instances of data with the identical Byte-address, i.e. the same code. The |
|
selection of a particular instance is purely based on the base-address in |
|
the segment register. |
|
|
|
In 32-bit mode the CPU provides 6 segments, which also support segment |
|
limits. The limits can be used to enforce address space protections. |
|
|
|
In 64-bit mode the CS/SS/DS/ES segments are ignored and the base address is |
|
always 0 to provide a full 64bit address space. The FS and GS segments are |
|
still functional in 64-bit mode. |
|
|
|
Common FS and GS usage |
|
------------------------------ |
|
|
|
The FS segment is commonly used to address Thread Local Storage (TLS). FS |
|
is usually managed by runtime code or a threading library. Variables |
|
declared with the '__thread' storage class specifier are instantiated per |
|
thread and the compiler emits the FS: address prefix for accesses to these |
|
variables. Each thread has its own FS base address so common code can be |
|
used without complex address offset calculations to access the per thread |
|
instances. Applications should not use FS for other purposes when they use |
|
runtimes or threading libraries which manage the per thread FS. |
|
|
|
The GS segment has no common use and can be used freely by |
|
applications. GCC and Clang support GS based addressing via address space |
|
identifiers. |
|
|
|
Reading and writing the FS/GS base address |
|
------------------------------------------ |
|
|
|
There exist two mechanisms to read and write the FS/GS base address: |
|
|
|
- the arch_prctl() system call |
|
|
|
- the FSGSBASE instruction family |
|
|
|
Accessing FS/GS base with arch_prctl() |
|
-------------------------------------- |
|
|
|
The arch_prctl(2) based mechanism is available on all 64-bit CPUs and all |
|
kernel versions. |
|
|
|
Reading the base: |
|
|
|
arch_prctl(ARCH_GET_FS, &fsbase); |
|
arch_prctl(ARCH_GET_GS, &gsbase); |
|
|
|
Writing the base: |
|
|
|
arch_prctl(ARCH_SET_FS, fsbase); |
|
arch_prctl(ARCH_SET_GS, gsbase); |
|
|
|
The ARCH_SET_GS prctl may be disabled depending on kernel configuration |
|
and security settings. |
|
|
|
Accessing FS/GS base with the FSGSBASE instructions |
|
--------------------------------------------------- |
|
|
|
With the Ivy Bridge CPU generation Intel introduced a new set of |
|
instructions to access the FS and GS base registers directly from user |
|
space. These instructions are also supported on AMD Family 17H CPUs. The |
|
following instructions are available: |
|
|
|
=============== =========================== |
|
RDFSBASE %reg Read the FS base register |
|
RDGSBASE %reg Read the GS base register |
|
WRFSBASE %reg Write the FS base register |
|
WRGSBASE %reg Write the GS base register |
|
=============== =========================== |
|
|
|
The instructions avoid the overhead of the arch_prctl() syscall and allow |
|
more flexible usage of the FS/GS addressing modes in user space |
|
applications. This does not prevent conflicts between threading libraries |
|
and runtimes which utilize FS and applications which want to use it for |
|
their own purpose. |
|
|
|
FSGSBASE instructions enablement |
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
|
The instructions are enumerated in CPUID leaf 7, bit 0 of EBX. If |
|
available /proc/cpuinfo shows 'fsgsbase' in the flag entry of the CPUs. |
|
|
|
The availability of the instructions does not enable them |
|
automatically. The kernel has to enable them explicitly in CR4. The |
|
reason for this is that older kernels make assumptions about the values in |
|
the GS register and enforce them when GS base is set via |
|
arch_prctl(). Allowing user space to write arbitrary values to GS base |
|
would violate these assumptions and cause malfunction. |
|
|
|
On kernels which do not enable FSGSBASE the execution of the FSGSBASE |
|
instructions will fault with a #UD exception. |
|
|
|
The kernel provides reliable information about the enabled state in the |
|
ELF AUX vector. If the HWCAP2_FSGSBASE bit is set in the AUX vector, the |
|
kernel has FSGSBASE instructions enabled and applications can use them. |
|
The following code example shows how this detection works:: |
|
|
|
#include <sys/auxv.h> |
|
#include <elf.h> |
|
|
|
/* Will be eventually in asm/hwcap.h */ |
|
#ifndef HWCAP2_FSGSBASE |
|
#define HWCAP2_FSGSBASE (1 << 1) |
|
#endif |
|
|
|
.... |
|
|
|
unsigned val = getauxval(AT_HWCAP2); |
|
|
|
if (val & HWCAP2_FSGSBASE) |
|
printf("FSGSBASE enabled\n"); |
|
|
|
FSGSBASE instructions compiler support |
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
|
|
|
GCC version 4.6.4 and newer provide instrinsics for the FSGSBASE |
|
instructions. Clang 5 supports them as well. |
|
|
|
=================== =========================== |
|
_readfsbase_u64() Read the FS base register |
|
_readfsbase_u64() Read the GS base register |
|
_writefsbase_u64() Write the FS base register |
|
_writegsbase_u64() Write the GS base register |
|
=================== =========================== |
|
|
|
To utilize these instrinsics <immintrin.h> must be included in the source |
|
code and the compiler option -mfsgsbase has to be added. |
|
|
|
Compiler support for FS/GS based addressing |
|
------------------------------------------- |
|
|
|
GCC version 6 and newer provide support for FS/GS based addressing via |
|
Named Address Spaces. GCC implements the following address space |
|
identifiers for x86: |
|
|
|
========= ==================================== |
|
__seg_fs Variable is addressed relative to FS |
|
__seg_gs Variable is addressed relative to GS |
|
========= ==================================== |
|
|
|
The preprocessor symbols __SEG_FS and __SEG_GS are defined when these |
|
address spaces are supported. Code which implements fallback modes should |
|
check whether these symbols are defined. Usage example:: |
|
|
|
#ifdef __SEG_GS |
|
|
|
long data0 = 0; |
|
long data1 = 1; |
|
|
|
long __seg_gs *ptr; |
|
|
|
/* Check whether FSGSBASE is enabled by the kernel (HWCAP2_FSGSBASE) */ |
|
.... |
|
|
|
/* Set GS base to point to data0 */ |
|
_writegsbase_u64(&data0); |
|
|
|
/* Access offset 0 of GS */ |
|
ptr = 0; |
|
printf("data0 = %ld\n", *ptr); |
|
|
|
/* Set GS base to point to data1 */ |
|
_writegsbase_u64(&data1); |
|
/* ptr still addresses offset 0! */ |
|
printf("data1 = %ld\n", *ptr); |
|
|
|
|
|
Clang does not provide the GCC address space identifiers, but it provides |
|
address spaces via an attribute based mechanism in Clang 2.6 and newer |
|
versions: |
|
|
|
==================================== ===================================== |
|
__attribute__((address_space(256)) Variable is addressed relative to GS |
|
__attribute__((address_space(257)) Variable is addressed relative to FS |
|
==================================== ===================================== |
|
|
|
FS/GS based addressing with inline assembly |
|
------------------------------------------- |
|
|
|
In case the compiler does not support address spaces, inline assembly can |
|
be used for FS/GS based addressing mode:: |
|
|
|
mov %fs:offset, %reg |
|
mov %gs:offset, %reg |
|
|
|
mov %reg, %fs:offset |
|
mov %reg, %gs:offset
|
|
|