← Documents Documentation/arch/x86/x86_64/fsgs.rst GitHub 원문 ↗

Linux 6.18.37 · Architecture

Using FS and GS Segments in User-Space Applications

FS/GS base의 arch_prctl·FSGSBASE 접근과 compiler address-space 지원을 설명합니다.

Source pathDocumentation/arch/x86/x86_64/fsgs.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.

1. 요약·해설

원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.

요약과 해설

fsgs.rst:1-199

64-bit mode에서도 FS와 GS는 base-relative addressing을 제공하며 FS는 주로 TLS에, GS는 application 전용 data instance에 사용합니다.

`arch_prctl()`은 보편적인 interface이고 FSGSBASE instruction은 syscall 없이 base를 다룹니다. 사용 전 `HWCAP2_FSGSBASE`를 확인하고 GCC/Clang의 intrinsic·address-space 지원 또는 inline assembly를 선택해야 합니다.

2. 영어 원문 전체

번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.

원문 전체 펼치기
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 intrinsics for the FSGSBASE
129 instructions. Clang 5 supports them as well.
130
131 =================== ===========================
132 _readfsbase_u64() Read the FS base register
133 _readgsbase_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 intrinsics <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
200

3. 한국어 전문 번역

영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.

x86 segmentation과 FS/GS

1-24

이 문서는 `SPDX-License-Identifier: GPL-2.0`으로 배포됩니다. x86 architecture는 segmentation을 지원하며 memory-access instruction은 segment register 기반 addressing mode를 사용할 수 있습니다. segment 안의 byte는 다음 notation으로 address합니다: `Segment-register:Byte-address`.

segment base address를 Byte-address에 더해 access할 virtual address를 계산합니다. 따라서 같은 Byte-address와 동일한 code로 data instance 여러 개에 access할 수 있고, 어느 instance를 선택할지는 segment register의 base address만으로 결정됩니다.

32-bit mode에서 CPU는 여섯 segment를 제공하며 address-space protection에 사용할 수 있는 segment limit도 지원합니다.

64-bit mode에서는 full 64-bit address space를 제공하기 위해 CS/SS/DS/ES segment를 무시하고 base address를 항상 0으로 둡니다. FS와 GS segment는 64-bit mode에서도 계속 동작합니다.

FS의 TLS와 GS addressing

25-40

FS segment는 일반적으로 Thread Local Storage (TLS)를 address하는 데 사용하며 runtime code나 threading library가 관리합니다. `__thread` storage-class specifier로 선언한 variable은 thread마다 instance가 생기고 compiler가 access에 `FS:` address prefix를 생성합니다.

각 thread가 자체 FS base address를 가지므로 common code가 복잡한 address-offset 계산 없이 per-thread instance에 access할 수 있습니다. per-thread FS를 관리하는 runtime이나 threading library를 사용한다면 application은 FS를 다른 목적으로 사용하면 안 됩니다.

GS segment에는 보편적인 용도가 없어 application이 자유롭게 사용할 수 있습니다. GCC와 Clang은 address-space identifier로 GS-based addressing을 지원합니다.

arch_prctl()로 FS/GS base 접근

41-68

FS/GS base address를 읽고 쓰는 mechanism은 두 가지입니다.

  • `arch_prctl()` system call
  • FSGSBASE instruction family

`arch_prctl(2)` 기반 mechanism은 모든 64-bit CPU와 모든 kernel version에서 사용할 수 있습니다.

base를 읽는 call은 다음과 같습니다.

arch_prctl(ARCH_GET_FS, &fsbase);
arch_prctl(ARCH_GET_GS, &gsbase);

base를 쓰는 call은 다음과 같습니다.

arch_prctl(ARCH_SET_FS, fsbase);
arch_prctl(ARCH_SET_GS, gsbase);

`ARCH_SET_GS` prctl은 kernel configuration과 security setting에 따라 비활성화될 수 있습니다.

FSGSBASE instruction family

69-89

Intel은 Ivy Bridge CPU generation에서 userspace가 FS와 GS base register에 직접 access하는 새 instruction set을 도입했습니다. AMD Family 17H CPU도 이를 지원합니다.

instruction동작
`RDFSBASE %reg`FS base register를 읽습니다.
`RDGSBASE %reg`GS base register를 읽습니다.
`WRFSBASE %reg`FS base register를 씁니다.
`WRGSBASE %reg`GS base register를 씁니다.

이 instruction은 `arch_prctl()` syscall overhead를 피하고 userspace application이 FS/GS addressing mode를 더 유연하게 사용하도록 합니다. 다만 FS를 사용하는 threading library·runtime과 FS를 자체 용도로 쓰려는 application 사이의 conflict까지 막지는 않습니다.

FSGSBASE enablement 감지

90-124

FSGSBASE instruction은 CPUID leaf 7의 `EBX` bit 0에 enumerate됩니다. 사용할 수 있으면 `/proc/cpuinfo`의 CPU flag entry에 `fsgsbase`가 표시됩니다.

instruction availability만으로 자동 활성화되지는 않으며 kernel이 `CR4`에서 명시적으로 enable해야 합니다. 구형 kernel은 GS register value에 대해 가정하고 `arch_prctl()`로 GS base를 설정할 때 이를 강제합니다. userspace의 arbitrary GS base write를 허용하면 이 가정이 깨져 malfunction할 수 있기 때문입니다.

FSGSBASE를 enable하지 않은 kernel에서 해당 instruction을 실행하면 `#UD` exception으로 fault합니다.

kernel은 ELF AUX vector에 신뢰할 수 있는 enable 상태를 제공합니다. AUX vector에 `HWCAP2_FSGSBASE` bit가 설정되어 있으면 kernel이 FSGSBASE instruction을 enable한 것이므로 application이 사용할 수 있습니다. 감지 예제는 다음과 같습니다.

#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");

compiler intrinsic 지원

125-140

GCC 4.6.4 이상과 Clang 5는 FSGSBASE instruction intrinsic을 지원합니다.

intrinsic동작
`_readfsbase_u64()`FS base register를 읽습니다.
`_readgsbase_u64()`GS base register를 읽습니다.
`_writefsbase_u64()`FS base register를 씁니다.
`_writegsbase_u64()`GS base register를 씁니다.

이 intrinsic을 사용하려면 source code에 `<immintrin.h>`를 include하고 compiler option `-mfsgsbase`를 추가해야 합니다.

GCC named address space

141-179

GCC 6 이상은 Named Address Spaces로 FS/GS-based addressing을 지원합니다. x86용 address-space identifier는 다음과 같습니다.

identifieraddress 기준
`__seg_fs`variable을 FS relative로 address합니다.
`__seg_gs`variable을 GS relative로 address합니다.

이 address space를 지원하면 preprocessor symbol `__SEG_FS`와 `__SEG_GS`를 정의합니다. fallback mode를 구현하는 code는 symbol 정의 여부를 확인해야 합니다.

#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);

예제는 GS base를 `data0`에서 `data1`으로 바꿔도 `ptr`이 계속 GS offset 0을 나타내므로 같은 code가 서로 다른 data instance를 읽는 방식을 보여 줍니다.

Clang address-space attribute

180-188

Clang은 GCC address-space identifier를 제공하지 않지만 Clang 2.6 이상에서 attribute 기반 address space를 제공합니다.

attributeaddress 기준
`__attribute__((address_space(256)))`variable을 GS relative로 address합니다.
`__attribute__((address_space(257)))`variable을 FS relative로 address합니다.

inline assembly fallback

189-199

compiler가 address space를 지원하지 않으면 inline assembly로 FS/GS-based addressing mode를 사용할 수 있습니다.

mov %fs:offset, %reg
mov %gs:offset, %reg

mov %reg, %fs:offset
mov %reg, %gs:offset