Test for stack alignment.
[glibc.git] / linuxthreads / sysdeps / i386 / useldt.h
blob4ac82f1ab078bc912e0b9885bd3c28b0cca206c5
1 /* Special definitions for ix86 machine using segment register based
2 thread descriptor.
3 Copyright (C) 1998, 2000, 2001, 2002 Free Software Foundation, Inc.
4 This file is part of the GNU C Library.
5 Contributed by Ulrich Drepper <drepper@cygnus.com>.
7 The GNU C Library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public License as
9 published by the Free Software Foundation; either version 2.1 of the
10 License, or (at your option) any later version.
12 The GNU C Library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public
18 License along with the GNU C Library; see the file COPYING.LIB. If not,
19 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
22 #ifndef __ASSEMBLER__
23 #include <stddef.h> /* For offsetof. */
24 #include <stdlib.h> /* For abort(). */
25 #include <sysdep.h>
28 /* We don't want to include the kernel header. So duplicate the
29 information. */
31 /* Structure passed on `modify_ldt' call. */
32 struct modify_ldt_ldt_s
34 unsigned int entry_number;
35 unsigned long int base_addr;
36 unsigned int limit;
37 unsigned int seg_32bit:1;
38 unsigned int contents:2;
39 unsigned int read_exec_only:1;
40 unsigned int limit_in_pages:1;
41 unsigned int seg_not_present:1;
42 unsigned int useable:1;
43 unsigned int empty:25;
46 /* System call to set LDT entry. */
47 extern int __modify_ldt (int, struct modify_ldt_ldt_s *, size_t);
50 /* Return the thread descriptor for the current thread.
52 The contained asm must *not* be marked volatile since otherwise
53 assignments like
54 pthread_descr self = thread_self();
55 do not get optimized away. */
56 #define THREAD_SELF \
57 ({ \
58 register pthread_descr __self; \
59 __asm__ ("movl %%gs:%c1,%0" : "=r" (__self) \
60 : "i" (offsetof (struct _pthread_descr_struct, \
61 p_header.data.self))); \
62 __self; \
66 /* Initialize the thread-unique value. Two possible ways to do it. */
68 #define DO_MODIFY_LDT(descr, nr) \
69 ({ \
70 struct modify_ldt_ldt_s ldt_entry = \
71 { nr, (unsigned long int) (descr), 0xfffff /* 4GB in pages */, \
72 1, 0, 0, 1, 0, 1, 0 }; \
73 if (__modify_ldt (1, &ldt_entry, sizeof (ldt_entry)) != 0) \
74 abort (); \
75 asm ("movw %w0, %%gs" : : "q" (nr * 8 + 7)); \
78 #ifdef __PIC__
79 # define USETLS_EBX_ARG "r"
80 # define USETLS_LOAD_EBX "xchgl %1, %%ebx\n\t"
81 #else
82 # define USETLS_EBX_ARG "b"
83 # define USETLS_LOAD_EBX
84 #endif
86 /* When using the new set_thread_area call, we don't need to change %gs
87 because we inherited the value set up in the main thread by TLS setup.
88 We need to extract that value and set up the same segment in this
89 thread. */
90 #if USE_TLS
91 # define DO_SET_THREAD_AREA_REUSE(nr) 1
92 #else
93 /* Without TLS, we do the initialization of the main thread, where NR == 0. */
94 # define DO_SET_THREAD_AREA_REUSE(nr) (!__builtin_constant_p (nr) || (nr))
95 #endif
96 #define DO_SET_THREAD_AREA(descr, nr) \
97 ({ \
98 int __gs; \
99 if (DO_SET_THREAD_AREA_REUSE (nr)) \
101 asm ("movw %%gs, %w0" : "=q" (__gs)); \
102 struct modify_ldt_ldt_s ldt_entry = \
103 { (__gs & 0xffff) >> 3, \
104 (unsigned long int) (descr), 0xfffff /* 4GB in pages */, \
105 1, 0, 0, 1, 0, 1, 0 }; \
107 int __result; \
108 __asm (USETLS_LOAD_EBX \
109 "movl %2, %%eax\n\t" \
110 "int $0x80\n\t" \
111 USETLS_LOAD_EBX \
112 : "=&a" (__result) \
113 : USETLS_EBX_ARG (&ldt_entry), "i" (__NR_set_thread_area), \
114 "m" (ldt_entry) \
115 : "memory"); \
116 if (__result == 0) \
117 asm ("movw %w0, %%gs" :: "q" (__gs)); \
118 else \
119 __gs = -1; \
121 else \
123 struct modify_ldt_ldt_s ldt_entry = \
124 { -1, \
125 (unsigned long int) (descr), 0xfffff /* 4GB in pages */, \
126 1, 0, 0, 1, 0, 1, 0 }; \
127 int __result; \
128 __asm (USETLS_LOAD_EBX \
129 "movl %2, %%eax\n\t" \
130 "int $0x80\n\t" \
131 USETLS_LOAD_EBX \
132 : "=&a" (__result) \
133 : USETLS_EBX_ARG (&ldt_entry), "i" (__NR_set_thread_area), \
134 "m" (ldt_entry) \
135 : "memory"); \
136 if (__result == 0) \
138 __gs = (ldt_entry.entry_number << 3) + 3; \
139 asm ("movw %w0, %%gs" : : "q" (__gs)); \
141 else \
142 __gs = -1; \
144 __gs; \
147 #if defined __ASSUME_SET_THREAD_AREA_SYSCALL
148 # define INIT_THREAD_SELF(descr, nr) DO_SET_THREAD_AREA (descr, nr)
149 #elif defined __NR_set_thread_area
150 # define INIT_THREAD_SELF(descr, nr) \
151 ({ \
152 if (__builtin_expect (__have_no_set_thread_area, 0) \
153 || (DO_SET_THREAD_AREA (descr, DO_SET_THREAD_AREA_REUSE (nr)) == -1 \
154 && (__have_no_set_thread_area = 1))) \
155 DO_MODIFY_LDT (descr, nr); \
157 /* Defined in pspinlock.c. */
158 extern int __have_no_set_thread_area;
159 #else
160 # define INIT_THREAD_SELF(descr, nr) DO_MODIFY_LDT (descr, nr)
161 #endif
163 /* Free resources associated with thread descriptor. */
164 #ifdef __ASSUME_SET_THREAD_AREA_SYSCALL
165 #define FREE_THREAD(descr, nr) do { } while (0)
166 #elif defined __NR_set_thread_area
167 #define FREE_THREAD(descr, nr) \
169 int __gs; \
170 __asm__ __volatile__ ("movw %%gs, %w0" : "=q" (__gs)); \
171 if (__builtin_expect (__gs & 4, 0)) \
173 struct modify_ldt_ldt_s ldt_entry = \
174 { nr, 0, 0, 0, 0, 1, 0, 1, 0, 0 }; \
175 __modify_ldt (1, &ldt_entry, sizeof (ldt_entry)); \
178 #else
179 #define FREE_THREAD(descr, nr) \
181 struct modify_ldt_ldt_s ldt_entry = \
182 { nr, 0, 0, 0, 0, 1, 0, 1, 0, 0 }; \
183 __modify_ldt (1, &ldt_entry, sizeof (ldt_entry)); \
185 #endif
187 /* Read member of the thread descriptor directly. */
188 #define THREAD_GETMEM(descr, member) \
189 ({ \
190 __typeof__ (descr->member) __value; \
191 if (sizeof (__value) == 1) \
192 __asm__ __volatile__ ("movb %%gs:%P2,%b0" \
193 : "=q" (__value) \
194 : "0" (0), \
195 "i" (offsetof (struct _pthread_descr_struct, \
196 member))); \
197 else if (sizeof (__value) == 4) \
198 __asm__ __volatile__ ("movl %%gs:%P1,%0" \
199 : "=r" (__value) \
200 : "i" (offsetof (struct _pthread_descr_struct, \
201 member))); \
202 else \
204 if (sizeof (__value) != 8) \
205 /* There should not be any value with a size other than 1, 4 or 8. */\
206 abort (); \
208 __asm__ __volatile__ ("movl %%gs:%P1,%%eax\n\t" \
209 "movl %%gs:%P2,%%edx" \
210 : "=A" (__value) \
211 : "i" (offsetof (struct _pthread_descr_struct, \
212 member)), \
213 "i" (offsetof (struct _pthread_descr_struct, \
214 member) + 4)); \
216 __value; \
219 /* Same as THREAD_GETMEM, but the member offset can be non-constant. */
220 #define THREAD_GETMEM_NC(descr, member) \
221 ({ \
222 __typeof__ (descr->member) __value; \
223 if (sizeof (__value) == 1) \
224 __asm__ __volatile__ ("movb %%gs:(%2),%b0" \
225 : "=q" (__value) \
226 : "0" (0), \
227 "r" (offsetof (struct _pthread_descr_struct, \
228 member))); \
229 else if (sizeof (__value) == 4) \
230 __asm__ __volatile__ ("movl %%gs:(%1),%0" \
231 : "=r" (__value) \
232 : "r" (offsetof (struct _pthread_descr_struct, \
233 member))); \
234 else \
236 if (sizeof (__value) != 8) \
237 /* There should not be any value with a size other than 1, 4 or 8. */\
238 abort (); \
240 __asm__ __volatile__ ("movl %%gs:(%1),%%eax\n\t" \
241 "movl %%gs:4(%1),%%edx" \
242 : "=&A" (__value) \
243 : "r" (offsetof (struct _pthread_descr_struct, \
244 member))); \
246 __value; \
249 /* Same as THREAD_SETMEM, but the member offset can be non-constant. */
250 #define THREAD_SETMEM(descr, member, value) \
251 ({ \
252 __typeof__ (descr->member) __value = (value); \
253 if (sizeof (__value) == 1) \
254 __asm__ __volatile__ ("movb %0,%%gs:%P1" : \
255 : "q" (__value), \
256 "i" (offsetof (struct _pthread_descr_struct, \
257 member))); \
258 else if (sizeof (__value) == 4) \
259 __asm__ __volatile__ ("movl %0,%%gs:%P1" : \
260 : "r" (__value), \
261 "i" (offsetof (struct _pthread_descr_struct, \
262 member))); \
263 else \
265 if (sizeof (__value) != 8) \
266 /* There should not be any value with a size other than 1, 4 or 8. */\
267 abort (); \
269 __asm__ __volatile__ ("movl %%eax,%%gs:%P1\n\n" \
270 "movl %%edx,%%gs:%P2" : \
271 : "A" (__value), \
272 "i" (offsetof (struct _pthread_descr_struct, \
273 member)), \
274 "i" (offsetof (struct _pthread_descr_struct, \
275 member) + 4)); \
279 /* Set member of the thread descriptor directly. */
280 #define THREAD_SETMEM_NC(descr, member, value) \
281 ({ \
282 __typeof__ (descr->member) __value = (value); \
283 if (sizeof (__value) == 1) \
284 __asm__ __volatile__ ("movb %0,%%gs:(%1)" : \
285 : "q" (__value), \
286 "r" (offsetof (struct _pthread_descr_struct, \
287 member))); \
288 else if (sizeof (__value) == 4) \
289 __asm__ __volatile__ ("movl %0,%%gs:(%1)" : \
290 : "r" (__value), \
291 "r" (offsetof (struct _pthread_descr_struct, \
292 member))); \
293 else \
295 if (sizeof (__value) != 8) \
296 /* There should not be any value with a size other than 1, 4 or 8. */\
297 abort (); \
299 __asm__ __volatile__ ("movl %%eax,%%gs:(%1)\n\t" \
300 "movl %%edx,%%gs:4(%1)" : \
301 : "A" (__value), \
302 "r" (offsetof (struct _pthread_descr_struct, \
303 member))); \
306 #endif
308 #if __ASSUME_LDT_WORKS > 0
309 /* We want the OS to assign stack addresses. */
310 #define FLOATING_STACKS 1
312 /* Maximum size of the stack if the rlimit is unlimited. */
313 #define ARCH_STACK_MAX_SIZE 8*1024*1024
314 #endif