1 | /* THREAD_* accessors. x86_64 version. |
2 | Copyright (C) 2002-2023 Free Software Foundation, Inc. |
3 | This file is part of the GNU C Library. |
4 | |
5 | The GNU C Library is free software; you can redistribute it and/or |
6 | modify it under the terms of the GNU Lesser General Public |
7 | License as published by the Free Software Foundation; either |
8 | version 2.1 of the License, or (at your option) any later version. |
9 | |
10 | The GNU C Library is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | Lesser General Public License for more details. |
14 | |
15 | You should have received a copy of the GNU Lesser General Public |
16 | License along with the GNU C Library; if not, see |
17 | <https://www.gnu.org/licenses/>. */ |
18 | |
19 | /* Read member of the thread descriptor directly. */ |
20 | # define THREAD_GETMEM(descr, member) \ |
21 | ({ __typeof (descr->member) __value; \ |
22 | _Static_assert (sizeof (__value) == 1 \ |
23 | || sizeof (__value) == 4 \ |
24 | || sizeof (__value) == 8, \ |
25 | "size of per-thread data"); \ |
26 | if (sizeof (__value) == 1) \ |
27 | asm volatile ("movb %%fs:%P2,%b0" \ |
28 | : "=q" (__value) \ |
29 | : "0" (0), "i" (offsetof (struct pthread, member))); \ |
30 | else if (sizeof (__value) == 4) \ |
31 | asm volatile ("movl %%fs:%P1,%0" \ |
32 | : "=r" (__value) \ |
33 | : "i" (offsetof (struct pthread, member))); \ |
34 | else /* 8 */ \ |
35 | { \ |
36 | asm volatile ("movq %%fs:%P1,%q0" \ |
37 | : "=r" (__value) \ |
38 | : "i" (offsetof (struct pthread, member))); \ |
39 | } \ |
40 | __value; }) |
41 | |
42 | /* THREAD_GETMEM already forces a read. */ |
43 | #define THREAD_GETMEM_VOLATILE(descr, member) THREAD_GETMEM (descr, member) |
44 | |
45 | /* Same as THREAD_GETMEM, but the member offset can be non-constant. */ |
46 | # define THREAD_GETMEM_NC(descr, member, idx) \ |
47 | ({ __typeof (descr->member[0]) __value; \ |
48 | _Static_assert (sizeof (__value) == 1 \ |
49 | || sizeof (__value) == 4 \ |
50 | || sizeof (__value) == 8, \ |
51 | "size of per-thread data"); \ |
52 | if (sizeof (__value) == 1) \ |
53 | asm volatile ("movb %%fs:%P2(%q3),%b0" \ |
54 | : "=q" (__value) \ |
55 | : "0" (0), "i" (offsetof (struct pthread, member[0])), \ |
56 | "r" (idx)); \ |
57 | else if (sizeof (__value) == 4) \ |
58 | asm volatile ("movl %%fs:%P1(,%q2,4),%0" \ |
59 | : "=r" (__value) \ |
60 | : "i" (offsetof (struct pthread, member[0])), "r" (idx));\ |
61 | else /* 8 */ \ |
62 | { \ |
63 | asm volatile ("movq %%fs:%P1(,%q2,8),%q0" \ |
64 | : "=r" (__value) \ |
65 | : "i" (offsetof (struct pthread, member[0])), \ |
66 | "r" (idx)); \ |
67 | } \ |
68 | __value; }) |
69 | |
70 | |
71 | /* Loading addresses of objects on x86-64 needs to be treated special |
72 | when generating PIC code. */ |
73 | #ifdef __pic__ |
74 | # define IMM_MODE "nr" |
75 | #else |
76 | # define IMM_MODE "ir" |
77 | #endif |
78 | |
79 | |
80 | /* Set member of the thread descriptor directly. */ |
81 | # define THREAD_SETMEM(descr, member, value) \ |
82 | ({ \ |
83 | _Static_assert (sizeof (descr->member) == 1 \ |
84 | || sizeof (descr->member) == 4 \ |
85 | || sizeof (descr->member) == 8, \ |
86 | "size of per-thread data"); \ |
87 | if (sizeof (descr->member) == 1) \ |
88 | asm volatile ("movb %b0,%%fs:%P1" : \ |
89 | : "iq" (value), \ |
90 | "i" (offsetof (struct pthread, member))); \ |
91 | else if (sizeof (descr->member) == 4) \ |
92 | asm volatile ("movl %0,%%fs:%P1" : \ |
93 | : IMM_MODE (value), \ |
94 | "i" (offsetof (struct pthread, member))); \ |
95 | else /* 8 */ \ |
96 | { \ |
97 | /* Since movq takes a signed 32-bit immediate or a register source \ |
98 | operand, use "er" constraint for 32-bit signed integer constant \ |
99 | or register. */ \ |
100 | asm volatile ("movq %q0,%%fs:%P1" : \ |
101 | : "er" ((uint64_t) cast_to_integer (value)), \ |
102 | "i" (offsetof (struct pthread, member))); \ |
103 | }}) |
104 | |
105 | |
106 | /* Same as THREAD_SETMEM, but the member offset can be non-constant. */ |
107 | # define THREAD_SETMEM_NC(descr, member, idx, value) \ |
108 | ({ \ |
109 | _Static_assert (sizeof (descr->member[0]) == 1 \ |
110 | || sizeof (descr->member[0]) == 4 \ |
111 | || sizeof (descr->member[0]) == 8, \ |
112 | "size of per-thread data"); \ |
113 | if (sizeof (descr->member[0]) == 1) \ |
114 | asm volatile ("movb %b0,%%fs:%P1(%q2)" : \ |
115 | : "iq" (value), \ |
116 | "i" (offsetof (struct pthread, member[0])), \ |
117 | "r" (idx)); \ |
118 | else if (sizeof (descr->member[0]) == 4) \ |
119 | asm volatile ("movl %0,%%fs:%P1(,%q2,4)" : \ |
120 | : IMM_MODE (value), \ |
121 | "i" (offsetof (struct pthread, member[0])), \ |
122 | "r" (idx)); \ |
123 | else /* 8 */ \ |
124 | { \ |
125 | /* Since movq takes a signed 32-bit immediate or a register source \ |
126 | operand, use "er" constraint for 32-bit signed integer constant \ |
127 | or register. */ \ |
128 | asm volatile ("movq %q0,%%fs:%P1(,%q2,8)" : \ |
129 | : "er" ((uint64_t) cast_to_integer (value)), \ |
130 | "i" (offsetof (struct pthread, member[0])), \ |
131 | "r" (idx)); \ |
132 | }}) |
133 | |