]> git.ipfire.org Git - thirdparty/glibc.git/blame - linuxthreads/sysdeps/i386/useldt.h
Test for stack alignment.
[thirdparty/glibc.git] / linuxthreads / sysdeps / i386 / useldt.h
CommitLineData
00a2f9aa
UD
1/* Special definitions for ix86 machine using segment register based
2 thread descriptor.
739d440d 3 Copyright (C) 1998, 2000, 2001, 2002 Free Software Foundation, Inc.
00a2f9aa
UD
4 This file is part of the GNU C Library.
5 Contributed by Ulrich Drepper <drepper@cygnus.com>.
6
7 The GNU C Library is free software; you can redistribute it and/or
cc7375ce
RM
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
00a2f9aa
UD
10 License, or (at your option) any later version.
11
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
1d0ad773 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
cc7375ce 15 Lesser General Public License for more details.
00a2f9aa 16
cc7375ce 17 You should have received a copy of the GNU Lesser General Public
00a2f9aa
UD
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,
1d0ad773 20 Boston, MA 02111-1307, USA. */
00a2f9aa 21
78ce5a3b 22#ifndef __ASSEMBLER__
00a2f9aa 23#include <stddef.h> /* For offsetof. */
1d0ad773 24#include <stdlib.h> /* For abort(). */
d63c3a70 25#include <sysdep.h>
00a2f9aa
UD
26
27
1d0ad773
RM
28/* We don't want to include the kernel header. So duplicate the
29 information. */
00a2f9aa
UD
30
31/* Structure passed on `modify_ldt' call. */
32struct modify_ldt_ldt_s
33{
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;
44};
45
46/* System call to set LDT entry. */
47extern int __modify_ldt (int, struct modify_ldt_ldt_s *, size_t);
48
49
50/* Return the thread descriptor for the current thread.
51
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) \
c77ec56d
UD
60 : "i" (offsetof (struct _pthread_descr_struct, \
61 p_header.data.self))); \
00a2f9aa
UD
62 __self; \
63})
64
25cb6eb2 65
1d0ad773 66/* Initialize the thread-unique value. Two possible ways to do it. */
25cb6eb2
RM
67
68#define DO_MODIFY_LDT(descr, nr) \
d7e1ad05 69({ \
00a2f9aa 70 struct modify_ldt_ldt_s ldt_entry = \
1d0ad773
RM
71 { nr, (unsigned long int) (descr), 0xfffff /* 4GB in pages */, \
72 1, 0, 0, 1, 0, 1, 0 }; \
00a2f9aa
UD
73 if (__modify_ldt (1, &ldt_entry, sizeof (ldt_entry)) != 0) \
74 abort (); \
c761cdf5 75 asm ("movw %w0, %%gs" : : "q" (nr * 8 + 7)); \
d7e1ad05
UD
76})
77
3ae5121b
UD
78#ifdef __PIC__
79# define USETLS_EBX_ARG "r"
8e96ae1a 80# define USETLS_LOAD_EBX "xchgl %1, %%ebx\n\t"
3ae5121b
UD
81#else
82# define USETLS_EBX_ARG "b"
83# define USETLS_LOAD_EBX
84#endif
85
25cb6eb2
RM
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. */
3ae5121b
UD
90#if USE_TLS
91# define DO_SET_THREAD_AREA_REUSE(nr) 1
92#else
de9a5225 93/* Without TLS, we do the initialization of the main thread, where NR == 0. */
3ae5121b
UD
94# define DO_SET_THREAD_AREA_REUSE(nr) (!__builtin_constant_p (nr) || (nr))
95#endif
96#define DO_SET_THREAD_AREA(descr, nr) \
25cb6eb2
RM
97({ \
98 int __gs; \
de9a5225
RM
99 if (DO_SET_THREAD_AREA_REUSE (nr)) \
100 { \
101 asm ("movw %%gs, %w0" : "=q" (__gs)); \
102 struct modify_ldt_ldt_s ldt_entry = \
103 { (__gs & 0xffff) >> 3, \
1d0ad773
RM
104 (unsigned long int) (descr), 0xfffff /* 4GB in pages */, \
105 1, 0, 0, 1, 0, 1, 0 }; \
3ae5121b
UD
106 \
107 int __result; \
108 __asm (USETLS_LOAD_EBX \
109 "movl %2, %%eax\n\t" \
110 "int $0x80\n\t" \
111 USETLS_LOAD_EBX \
8e96ae1a 112 : "=&a" (__result) \
2626ed6c
UD
113 : USETLS_EBX_ARG (&ldt_entry), "i" (__NR_set_thread_area), \
114 "m" (ldt_entry) \
115 : "memory"); \
3ae5121b 116 if (__result == 0) \
de9a5225
RM
117 asm ("movw %w0, %%gs" :: "q" (__gs)); \
118 else \
119 __gs = -1; \
120 } \
c761cdf5 121 else \
de9a5225
RM
122 { \
123 struct modify_ldt_ldt_s ldt_entry = \
124 { -1, \
1d0ad773
RM
125 (unsigned long int) (descr), 0xfffff /* 4GB in pages */, \
126 1, 0, 0, 1, 0, 1, 0 }; \
3ae5121b
UD
127 int __result; \
128 __asm (USETLS_LOAD_EBX \
129 "movl %2, %%eax\n\t" \
130 "int $0x80\n\t" \
131 USETLS_LOAD_EBX \
8e96ae1a 132 : "=&a" (__result) \
2626ed6c
UD
133 : USETLS_EBX_ARG (&ldt_entry), "i" (__NR_set_thread_area), \
134 "m" (ldt_entry) \
135 : "memory"); \
3ae5121b 136 if (__result == 0) \
de9a5225
RM
137 { \
138 __gs = (ldt_entry.entry_number << 3) + 3; \
139 asm ("movw %w0, %%gs" : : "q" (__gs)); \
140 } \
141 else \
142 __gs = -1; \
143 } \
144 __gs; \
25cb6eb2 145})
d7e1ad05 146
de9a5225
RM
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
25cb6eb2
RM
150# define INIT_THREAD_SELF(descr, nr) \
151({ \
152 if (__builtin_expect (__have_no_set_thread_area, 0) \
de9a5225 153 || (DO_SET_THREAD_AREA (descr, DO_SET_THREAD_AREA_REUSE (nr)) == -1 \
25cb6eb2
RM
154 && (__have_no_set_thread_area = 1))) \
155 DO_MODIFY_LDT (descr, nr); \
156})
d7e1ad05
UD
157/* Defined in pspinlock.c. */
158extern int __have_no_set_thread_area;
d7e1ad05 159#else
25cb6eb2 160# define INIT_THREAD_SELF(descr, nr) DO_MODIFY_LDT (descr, nr)
d7e1ad05 161#endif
00a2f9aa
UD
162
163/* Free resources associated with thread descriptor. */
d7e1ad05
UD
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) \
168{ \
169 int __gs; \
c761cdf5 170 __asm__ __volatile__ ("movw %%gs, %w0" : "=q" (__gs)); \
d7e1ad05
UD
171 if (__builtin_expect (__gs & 4, 0)) \
172 { \
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)); \
176 } \
177}
178#else
9bf4d640 179#define FREE_THREAD(descr, nr) \
00a2f9aa
UD
180{ \
181 struct modify_ldt_ldt_s ldt_entry = \
182 { nr, 0, 0, 0, 0, 1, 0, 1, 0, 0 }; \
00a2f9aa
UD
183 __modify_ldt (1, &ldt_entry, sizeof (ldt_entry)); \
184}
d7e1ad05 185#endif
00a2f9aa
UD
186
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) \
75311719 192 __asm__ __volatile__ ("movb %%gs:%P2,%b0" \
9bf4d640 193 : "=q" (__value) \
00a2f9aa
UD
194 : "0" (0), \
195 "i" (offsetof (struct _pthread_descr_struct, \
196 member))); \
5fc48cd7
UD
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))); \
00a2f9aa
UD
202 else \
203 { \
5fc48cd7
UD
204 if (sizeof (__value) != 8) \
205 /* There should not be any value with a size other than 1, 4 or 8. */\
00a2f9aa
UD
206 abort (); \
207 \
5fc48cd7
UD
208 __asm__ __volatile__ ("movl %%gs:%P1,%%eax\n\t" \
209 "movl %%gs:%P2,%%edx" \
210 : "=A" (__value) \
00a2f9aa 211 : "i" (offsetof (struct _pthread_descr_struct, \
5fc48cd7
UD
212 member)), \
213 "i" (offsetof (struct _pthread_descr_struct, \
214 member) + 4)); \
00a2f9aa
UD
215 } \
216 __value; \
217})
218
75311719
UD
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" \
9bf4d640 225 : "=q" (__value) \
75311719
UD
226 : "0" (0), \
227 "r" (offsetof (struct _pthread_descr_struct, \
228 member))); \
5fc48cd7
UD
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))); \
75311719
UD
234 else \
235 { \
5fc48cd7
UD
236 if (sizeof (__value) != 8) \
237 /* There should not be any value with a size other than 1, 4 or 8. */\
75311719
UD
238 abort (); \
239 \
5fc48cd7
UD
240 __asm__ __volatile__ ("movl %%gs:(%1),%%eax\n\t" \
241 "movl %%gs:4(%1),%%edx" \
242 : "=&A" (__value) \
75311719
UD
243 : "r" (offsetof (struct _pthread_descr_struct, \
244 member))); \
245 } \
246 __value; \
247})
248
249/* Same as THREAD_SETMEM, but the member offset can be non-constant. */
00a2f9aa
UD
250#define THREAD_SETMEM(descr, member, value) \
251({ \
252 __typeof__ (descr->member) __value = (value); \
253 if (sizeof (__value) == 1) \
f787edde 254 __asm__ __volatile__ ("movb %0,%%gs:%P1" : \
9bf4d640 255 : "q" (__value), \
00a2f9aa
UD
256 "i" (offsetof (struct _pthread_descr_struct, \
257 member))); \
5fc48cd7
UD
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))); \
00a2f9aa
UD
263 else \
264 { \
5fc48cd7
UD
265 if (sizeof (__value) != 8) \
266 /* There should not be any value with a size other than 1, 4 or 8. */\
00a2f9aa
UD
267 abort (); \
268 \
5fc48cd7
UD
269 __asm__ __volatile__ ("movl %%eax,%%gs:%P1\n\n" \
270 "movl %%edx,%%gs:%P2" : \
271 : "A" (__value), \
00a2f9aa 272 "i" (offsetof (struct _pthread_descr_struct, \
5fc48cd7
UD
273 member)), \
274 "i" (offsetof (struct _pthread_descr_struct, \
275 member) + 4)); \
00a2f9aa
UD
276 } \
277})
75311719
UD
278
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)" : \
9bf4d640 285 : "q" (__value), \
75311719
UD
286 "r" (offsetof (struct _pthread_descr_struct, \
287 member))); \
5fc48cd7
UD
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))); \
75311719
UD
293 else \
294 { \
5fc48cd7
UD
295 if (sizeof (__value) != 8) \
296 /* There should not be any value with a size other than 1, 4 or 8. */\
75311719
UD
297 abort (); \
298 \
5fc48cd7
UD
299 __asm__ __volatile__ ("movl %%eax,%%gs:(%1)\n\t" \
300 "movl %%edx,%%gs:4(%1)" : \
301 : "A" (__value), \
75311719
UD
302 "r" (offsetof (struct _pthread_descr_struct, \
303 member))); \
304 } \
305})
739d440d 306#endif
234dd7a6 307
99326cd4 308#if __ASSUME_LDT_WORKS > 0
234dd7a6
UD
309/* We want the OS to assign stack addresses. */
310#define FLOATING_STACKS 1
311
8d42e2e5 312/* Maximum size of the stack if the rlimit is unlimited. */
234dd7a6 313#define ARCH_STACK_MAX_SIZE 8*1024*1024
99326cd4 314#endif