1 /* THREAD_* accessors.  i386 version.
2    Copyright (C) 2002-2022 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 %%gs:%P2,%b0"				      \
28 		     : "=q" (__value)					      \
29 		     : "0" (0), "i" (offsetof (struct pthread, member)));     \
30      else if (sizeof (__value) == 4)					      \
31        asm volatile ("movl %%gs:%P1,%0"					      \
32 		     : "=r" (__value)					      \
33 		     : "i" (offsetof (struct pthread, member)));	      \
34      else /* 8 */								      \
35        {								      \
36 	 asm volatile ("movl %%gs:%P1,%%eax\n\t"			      \
37 		       "movl %%gs:%P2,%%edx"				      \
38 		       : "=A" (__value)					      \
39 		       : "i" (offsetof (struct pthread, member)),	      \
40 			 "i" (offsetof (struct pthread, member) + 4));	      \
41        }								      \
42      __value; })
43 
44 /* THREAD_GETMEM already forces a read.  */
45 #define THREAD_GETMEM_VOLATILE(descr, member) THREAD_GETMEM (descr, member)
46 
47 /* Same as THREAD_GETMEM, but the member offset can be non-constant.  */
48 #define THREAD_GETMEM_NC(descr, member, idx) \
49   ({ __typeof (descr->member[0]) __value;				      \
50      _Static_assert (sizeof (__value) == 1				      \
51 		     || sizeof (__value) == 4				      \
52 		     || sizeof (__value) == 8,				      \
53 		     "size of per-thread data");			      \
54      if (sizeof (__value) == 1)						      \
55        asm volatile ("movb %%gs:%P2(%3),%b0"				      \
56 		     : "=q" (__value)					      \
57 		     : "0" (0), "i" (offsetof (struct pthread, member[0])),   \
58 		     "r" (idx));					      \
59      else if (sizeof (__value) == 4)					      \
60        asm volatile ("movl %%gs:%P1(,%2,4),%0"				      \
61 		     : "=r" (__value)					      \
62 		     : "i" (offsetof (struct pthread, member[0])),	      \
63 		       "r" (idx));					      \
64      else /* 8 */							      \
65        {								      \
66 	 asm volatile  ("movl %%gs:%P1(,%2,8),%%eax\n\t"		      \
67 			"movl %%gs:4+%P1(,%2,8),%%edx"			      \
68 			: "=&A" (__value)				      \
69 			: "i" (offsetof (struct pthread, member[0])),	      \
70 			  "r" (idx));					      \
71        }								      \
72      __value; })
73 
74 
75 
76 /* Set member of the thread descriptor directly.  */
77 #define THREAD_SETMEM(descr, member, value) \
78   ({									      \
79      _Static_assert (sizeof (descr->member) == 1			      \
80 		     || sizeof (descr->member) == 4			      \
81 		     || sizeof (descr->member) == 8,			      \
82 		     "size of per-thread data");			      \
83      if (sizeof (descr->member) == 1)					      \
84        asm volatile ("movb %b0,%%gs:%P1" :				      \
85 		     : "iq" (value),					      \
86 		       "i" (offsetof (struct pthread, member)));	      \
87      else if (sizeof (descr->member) == 4)				      \
88        asm volatile ("movl %0,%%gs:%P1" :				      \
89 		     : "ir" (value),					      \
90 		       "i" (offsetof (struct pthread, member)));	      \
91      else /* 8 */							      \
92        {								      \
93 	 asm volatile ("movl %%eax,%%gs:%P1\n\t"			      \
94 		       "movl %%edx,%%gs:%P2" :				      \
95 		       : "A" ((uint64_t) cast_to_integer (value)),	      \
96 			 "i" (offsetof (struct pthread, member)),	      \
97 			 "i" (offsetof (struct pthread, member) + 4));	      \
98        }})
99 
100 
101 /* Same as THREAD_SETMEM, but the member offset can be non-constant.  */
102 #define THREAD_SETMEM_NC(descr, member, idx, value) \
103   ({									      \
104      _Static_assert (sizeof (descr->member[0]) == 1			      \
105 		     || sizeof (descr->member[0]) == 4			      \
106 		     || sizeof (descr->member[0]) == 8,			      \
107 		     "size of per-thread data");			      \
108      if (sizeof (descr->member[0]) == 1)				      \
109        asm volatile ("movb %b0,%%gs:%P1(%2)" :				      \
110 		     : "iq" (value),					      \
111 		       "i" (offsetof (struct pthread, member)),		      \
112 		       "r" (idx));					      \
113      else if (sizeof (descr->member[0]) == 4)				      \
114        asm volatile ("movl %0,%%gs:%P1(,%2,4)" :			      \
115 		     : "ir" (value),					      \
116 		       "i" (offsetof (struct pthread, member)),		      \
117 		       "r" (idx));					      \
118      else /* 8 */							      \
119        {								      \
120 	 asm volatile ("movl %%eax,%%gs:%P1(,%2,8)\n\t"			      \
121 		       "movl %%edx,%%gs:4+%P1(,%2,8)" :			      \
122 		       : "A" ((uint64_t) cast_to_integer (value)),	      \
123 			 "i" (offsetof (struct pthread, member)),	      \
124 			 "r" (idx));					      \
125        }})
126