1 /* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Jakub Jelinek <jakub@redhat.com>, 2002.
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.
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.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
23 # include <nptl/pthreadP.h>
26 #if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt
29 # define PSEUDO(name, syscall_name, args) \
33 cmpl $0, %gs:MULTIPLE_THREADS_OFFSET; \
34 jne L(pseudo_cancel); \
35 .type __##syscall_name##_nocancel,@function; \
36 .globl __##syscall_name##_nocancel; \
37 __##syscall_name##_nocancel: \
38 DO_CALL (syscall_name, args); \
40 jae SYSCALL_ERROR_LABEL; \
42 .size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel; \
48 movl $SYS_ify (syscall_name), %eax; \
53 jae SYSCALL_ERROR_LABEL; \
56 /* Create unwinding information for the syscall wrapper. */ \
57 .section .eh_frame,"a",@progbits; \
59 /* Length of the CIE. */ \
60 .long L(ENDCIE)-L(STARTCIE); \
64 /* Version number. */ \
66 /* NUL-terminated augmentation string. */ \
67 AUGMENTATION_STRING; \
68 /* Code alignment factor. */ \
70 /* Data alignment factor. */ \
72 /* Return address register column. */ \
74 /* Optional augmentation parameter. */ \
76 /* Start of the table initialization. */ \
77 .byte 0xc; /* DW_CFA_def_cfa */ \
80 .byte 0x88; /* DW_CFA_offset, column 0x8 */ \
84 /* Length of the FDE. */ \
85 .long L(ENDFDE)-L(STARTFDE); \
88 .long L(STARTFDE)-L(STARTFRAME); \
89 /* Start address of the code. */ \
90 START_SYMBOL_REF (name); \
91 /* Length of the code. */ \
92 .long L(name##END)-L(name##START); \
93 /* Augmentation data. */ \
94 AUGMENTATION_PARAM_FDE \
95 /* The rest of the code depends on the number of parameters the syscall \
97 EH_FRAME_##args(name); \
103 /* NUL-terminated augmentation string. Note "z" means there is an
104 augmentation value later on. */
105 # define AUGMENTATION_STRING .string "zR"
106 # define AUGMENTATION_PARAM \
107 /* Augmentation value length. */ \
109 /* Encoding: DW_EH_PE_pcrel + DW_EH_PE_sdata4. */ \
111 # define AUGMENTATION_PARAM_FDE \
112 /* No augmentation data. */ \
114 # define START_SYMBOL_REF(name) \
115 /* PC-relative start address of the code. */ \
116 .long L(name##START)-.
118 /* No augmentation. */
119 # define AUGMENTATION_STRING .ascii "\0"
120 # define AUGMENTATION_PARAM /* nothing */
121 # define AUGMENTATION_PARAM_FDE /* nothing */
122 # define START_SYMBOL_REF(name) \
123 /* Absolute start address of the code. */ \
127 /* Callframe description for syscalls without parameters. This is very
128 simple. The only place the stack pointer is changed is when the old
129 cancellation state value is saved. */
130 # define EH_FRAME_0(name) \
131 .byte 0x40+L(PUSHSTATE)-L(name##START); /* DW_CFA_advance_loc+N */ \
132 .byte 14; /* DW_CFA_def_cfa_offset */ \
134 .byte 0x40+L(POPSTATE)-L(PUSHSTATE); /* DW_CFA_advance_loc+N */ \
135 .byte 14; /* DW_CFA_def_cfa_offset */ \
138 /* For syscalls with one and two parameters the code is the same as for
139 those which take no parameter. */
140 # define EH_FRAME_1(name) \
141 .byte 0x40+L(SAVEBX1)-L(name##START); /* DW_CFA_advance_loc+N */ \
142 .byte 9; /* DW_CFA_register */ \
143 .uleb128 3; /* %ebx */ \
144 .uleb128 2; /* %edx */ \
145 .byte 0x40+L(RESTBX1)-L(SAVEBX1); /* DW_CFA_advance_loc+N */ \
146 .byte 0xc3; /* DW_CFA_restore %ebx */ \
147 .byte 0x40+L(PUSHSTATE)-L(RESTBX1); /* DW_CFA_advance_loc+N */ \
148 .byte 14; /* DW_CFA_def_cfa_offset */ \
150 .byte 0x40+L(SAVEBX2)-L(PUSHSTATE); /* DW_CFA_advance_loc+N */ \
151 .byte 9; /* DW_CFA_register */ \
152 .uleb128 3; /* %ebx */ \
153 .uleb128 2; /* %edx */ \
154 .byte 0x40+L(RESTBX2)-L(SAVEBX2); /* DW_CFA_advance_loc+N */ \
155 .byte 0xc3; /* DW_CFA_restore %ebx */ \
156 .byte 0x40+L(POPSTATE)-L(RESTBX2); /* DW_CFA_advance_loc+N */ \
157 .byte 14; /* DW_CFA_def_cfa_offset */ \
160 # define EH_FRAME_2(name) EH_FRAME_1 (name)
162 /* For syscalls with three parameters the stack pointer is changed
163 also to save the content of the %ebx register. */
164 # define EH_FRAME_3(name) \
165 .byte 0x40+L(PUSHBX1)-L(name##START); /* DW_CFA_advance_loc+N */ \
166 .byte 14; /* DW_CFA_def_cfa_offset */ \
168 .byte 0x83; /* DW_CFA_offset %ebx */ \
170 .byte 0x40+L(POPBX1)-L(PUSHBX1); /* DW_CFA_advance_loc+N */ \
171 .byte 14; /* DW_CFA_def_cfa_offset */ \
173 .byte 0xc3; /* DW_CFA_restore %ebx */ \
174 .byte 0x40+L(PUSHSTATE)-L(POPBX1); /* DW_CFA_advance_loc+N */ \
175 .byte 14; /* DW_CFA_def_cfa_offset */ \
177 .byte 0x40+L(PUSHBX2)-L(PUSHSTATE); /* DW_CFA_advance_loc+N */ \
178 .byte 14; /* DW_CFA_def_cfa_offset */ \
180 .byte 0x83; /* DW_CFA_offset %ebx */ \
182 .byte 0x40+L(POPBX2)-L(PUSHBX2); /* DW_CFA_advance_loc+N */ \
183 .byte 14; /* DW_CFA_def_cfa_offset */ \
185 .byte 0xc3; /* DW_CFA_restore %ebx */ \
186 .byte 0x40+L(POPSTATE)-L(POPBX2); /* DW_CFA_advance_loc+N */ \
187 .byte 14; /* DW_CFA_def_cfa_offset */ \
190 /* With four parameters the syscall wrappers have to save %ebx and %esi. */
191 # define EH_FRAME_4(name) \
192 .byte 0x40+L(PUSHSI1)-L(name##START); /* DW_CFA_advance_loc+N */ \
193 .byte 14; /* DW_CFA_def_cfa_offset */ \
195 .byte 0x86; /* DW_CFA_offset %esi */ \
197 .byte 0x40+L(PUSHBX1)-L(PUSHSI1); /* DW_CFA_advance_loc+N */ \
198 .byte 14; /* DW_CFA_def_cfa_offset */ \
200 .byte 0x83; /* DW_CFA_offset %ebx */ \
202 .byte 0x40+L(POPBX1)-L(PUSHBX1); /* DW_CFA_advance_loc+N */ \
203 .byte 14; /* DW_CFA_def_cfa_offset */ \
205 .byte 0xc3; /* DW_CFA_restore %ebx */ \
206 .byte 0x40+L(POPSI1)-L(POPBX1); /* DW_CFA_advance_loc+N */ \
207 .byte 14; /* DW_CFA_def_cfa_offset */ \
209 .byte 0xc6; /* DW_CFA_restore %esi */ \
210 .byte 0x40+L(PUSHSTATE)-L(POPSI1); /* DW_CFA_advance_loc+N */ \
211 .byte 14; /* DW_CFA_def_cfa_offset */ \
213 .byte 0x40+L(PUSHSI2)-L(PUSHSTATE); /* DW_CFA_advance_loc+N */ \
214 .byte 14; /* DW_CFA_def_cfa_offset */ \
216 .byte 0x86; /* DW_CFA_offset %esi */ \
218 .byte 0x40+L(PUSHBX2)-L(PUSHSI2); /* DW_CFA_advance_loc+N */ \
219 .byte 14; /* DW_CFA_def_cfa_offset */ \
221 .byte 0x83; /* DW_CFA_offset %ebx */ \
223 .byte 0x40+L(POPBX2)-L(PUSHBX2); /* DW_CFA_advance_loc+N */ \
224 .byte 14; /* DW_CFA_def_cfa_offset */ \
226 .byte 0xc3; /* DW_CFA_restore %ebx */ \
227 .byte 0x40+L(POPSI2)-L(POPBX2); /* DW_CFA_advance_loc+N */ \
228 .byte 14; /* DW_CFA_def_cfa_offset */ \
230 .byte 0xc6; /* DW_CFA_restore %esi */ \
231 .byte 0x40+L(POPSTATE)-L(POPSI2); /* DW_CFA_advance_loc+N */ \
232 .byte 14; /* DW_CFA_def_cfa_offset */ \
235 /* With five parameters the syscall wrappers have to save %ebx, %esi,
237 # define EH_FRAME_5(name) \
238 .byte 0x40+L(PUSHDI1)-L(name##START); /* DW_CFA_advance_loc+N */ \
239 .byte 14; /* DW_CFA_def_cfa_offset */ \
241 .byte 0x87; /* DW_CFA_offset %edi */ \
243 .byte 0x40+L(PUSHSI1)-L(PUSHDI1); /* DW_CFA_advance_loc+N */ \
244 .byte 14; /* DW_CFA_def_cfa_offset */ \
246 .byte 0x86; /* DW_CFA_offset %esi */ \
248 .byte 0x40+L(PUSHBX1)-L(PUSHSI1); /* DW_CFA_advance_loc+N */ \
249 .byte 14; /* DW_CFA_def_cfa_offset */ \
251 .byte 0x83; /* DW_CFA_offset %ebx */ \
253 .byte 0x40+L(POPBX1)-L(PUSHBX1); /* DW_CFA_advance_loc+N */ \
254 .byte 14; /* DW_CFA_def_cfa_offset */ \
256 .byte 0xc3; /* DW_CFA_restore %ebx */ \
257 .byte 0x40+L(POPSI1)-L(POPBX1); /* DW_CFA_advance_loc+N */ \
258 .byte 14; /* DW_CFA_def_cfa_offset */ \
260 .byte 0xc6; /* DW_CFA_restore %esi */ \
261 .byte 0x40+L(POPDI1)-L(POPSI1); /* DW_CFA_advance_loc+N */ \
262 .byte 14; /* DW_CFA_def_cfa_offset */ \
264 .byte 0xc7; /* DW_CFA_restore %edi */ \
265 .byte 0x40+L(PUSHSTATE)-L(POPDI1); /* DW_CFA_advance_loc+N */ \
266 .byte 14; /* DW_CFA_def_cfa_offset */ \
268 .byte 0x40+L(PUSHDI2)-L(PUSHSTATE); /* DW_CFA_advance_loc+N */ \
269 .byte 14; /* DW_CFA_def_cfa_offset */ \
271 .byte 0x87; /* DW_CFA_offset %edi */ \
273 .byte 0x40+L(PUSHSI2)-L(PUSHDI2); /* DW_CFA_advance_loc+N */ \
274 .byte 14; /* DW_CFA_def_cfa_offset */ \
276 .byte 0x86; /* DW_CFA_offset %esi */ \
278 .byte 0x40+L(PUSHBX2)-L(PUSHSI2); /* DW_CFA_advance_loc+N */ \
279 .byte 14; /* DW_CFA_def_cfa_offset */ \
281 .byte 0x83; /* DW_CFA_offset %ebx */ \
283 .byte 0x40+L(POPBX2)-L(PUSHBX2); /* DW_CFA_advance_loc+N */ \
284 .byte 14; /* DW_CFA_def_cfa_offset */ \
286 .byte 0xc3; /* DW_CFA_restore %ebx */ \
287 .byte 0x40+L(POPSI2)-L(POPBX2); /* DW_CFA_advance_loc+N */ \
288 .byte 14; /* DW_CFA_def_cfa_offset */ \
290 .byte 0xc6; /* DW_CFA_restore %esi */ \
291 .byte 0x40+L(POPDI2)-L(POPSI2); /* DW_CFA_advance_loc+N */ \
292 .byte 14; /* DW_CFA_def_cfa_offset */ \
294 .byte 0xc7; /* DW_CFA_restore %edi */ \
295 .byte 0x40+L(POPSTATE)-L(POPDI2); /* DW_CFA_advance_loc+N */ \
296 .byte 14; /* DW_CFA_def_cfa_offset */ \
300 # undef ASM_SIZE_DIRECTIVE
301 # define ASM_SIZE_DIRECTIVE(name) L(name##END): .size name,.-name;
303 # define SAVE_OLDTYPE_0 movl %eax, %ecx;
304 # define SAVE_OLDTYPE_1 SAVE_OLDTYPE_0
305 # define SAVE_OLDTYPE_2 pushl %eax; L(PUSHSTATE):
306 # define SAVE_OLDTYPE_3 SAVE_OLDTYPE_2
307 # define SAVE_OLDTYPE_4 SAVE_OLDTYPE_2
308 # define SAVE_OLDTYPE_5 SAVE_OLDTYPE_2
310 # define PUSHCARGS_0 /* No arguments to push. */
311 # define DOCARGS_0 /* No arguments to frob. */
312 # define POPCARGS_0 /* No arguments to pop. */
313 # define _PUSHCARGS_0 /* No arguments to push. */
314 # define _POPCARGS_0 /* No arguments to pop. */
316 # define PUSHCARGS_1 movl %ebx, %edx; L(SAVEBX2): PUSHCARGS_0
317 # define DOCARGS_1 _DOARGS_1 (4)
318 # define POPCARGS_1 POPCARGS_0; movl %edx, %ebx; L(RESTBX2):
319 # define _PUSHCARGS_1 pushl %ebx; L(PUSHBX2): _PUSHCARGS_0
320 # define _POPCARGS_1 _POPCARGS_0; popl %ebx; L(POPBX2):
322 # define PUSHCARGS_2 PUSHCARGS_1
323 # define DOCARGS_2 _DOARGS_2 (12)
324 # define POPCARGS_2 POPCARGS_1
325 # define _PUSHCARGS_2 _PUSHCARGS_1
326 # define _POPCARGS_2 _POPCARGS_1
328 # define PUSHCARGS_3 _PUSHCARGS_2
329 # define DOCARGS_3 _DOARGS_3 (20)
330 # define POPCARGS_3 _POPCARGS_3
331 # define _PUSHCARGS_3 _PUSHCARGS_2
332 # define _POPCARGS_3 _POPCARGS_2
334 # define PUSHCARGS_4 _PUSHCARGS_4
335 # define DOCARGS_4 _DOARGS_4 (28)
336 # define POPCARGS_4 _POPCARGS_4
337 # define _PUSHCARGS_4 pushl %esi; L(PUSHSI2): _PUSHCARGS_3
338 # define _POPCARGS_4 _POPCARGS_3; popl %esi; L(POPSI2):
340 # define PUSHCARGS_5 _PUSHCARGS_5
341 # define DOCARGS_5 _DOARGS_5 (36)
342 # define POPCARGS_5 _POPCARGS_5
343 # define _PUSHCARGS_5 pushl %edi; L(PUSHDI2): _PUSHCARGS_4
344 # define _POPCARGS_5 _POPCARGS_4; popl %edi; L(POPDI2):
346 # ifdef IS_IN_libpthread
347 # define CENABLE call __pthread_enable_asynccancel;
348 # define CDISABLE call __pthread_disable_asynccancel
349 # elif !defined NOT_IN_libc
350 # define CENABLE call __libc_enable_asynccancel;
351 # define CDISABLE call __libc_disable_asynccancel
352 # elif defined IS_IN_librt
353 # define CENABLE call __librt_enable_asynccancel;
354 # define CDISABLE call __librt_disable_asynccancel
356 # error Unsupported library
358 # define POPSTATE_0 \
359 pushl %eax; L(PUSHSTATE): movl %ecx, %eax; CDISABLE; popl %eax; L(POPSTATE):
360 # define POPSTATE_1 POPSTATE_0
361 # define POPSTATE_2 xchgl (%esp), %eax; CDISABLE; popl %eax; L(POPSTATE):
362 # define POPSTATE_3 POPSTATE_2
363 # define POPSTATE_4 POPSTATE_3
364 # define POPSTATE_5 POPSTATE_4
366 # ifndef __ASSEMBLER__
367 # define SINGLE_THREAD_P \
368 __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
369 header.multiple_threads) == 0, 1)
371 # define SINGLE_THREAD_P cmpl $0, %gs:MULTIPLE_THREADS_OFFSET
374 #elif !defined __ASSEMBLER__
376 # define SINGLE_THREAD_P (1)
377 # define NO_CANCELLATION 1